Compare commits

...

1126 Commits

Author SHA1 Message Date
rustdesk
24a16d9a30 fix: address codex review findings on probe/watchdog fallback
- a probe or raster-stall failure record now also downgrades sessions
  that are already running: main_set_local_option broadcasts the
  fallback for failed-* health writes, which also closes the hole where
  the watchdog's idempotence guard no-oped after the probe had already
  written the record
- probe success requires a frame timing newer than the first push:
  'consumed' advances inside the plugin callback before the GL/Metal
  upload, so a raster thread hanging in the driver no longer counts as
  a pass (and cannot clear a previous failure)
- watchdog failures are tagged with the failing backend
  (failed-watchdog-rgba/gpu); the rgba-only probe clears only the rgba
  class, so a working pixel-buffer path can no longer re-enable a
  broken D3D shared-handle path every launch
- the watchdog pauses while the session's window is hidden (new
  session_set_render_visible FFI wired to the window minimize/restore
  events): a display registered in a minimized window no longer records
  a false global failure; observation now counts pushes within the
  window rather than since registration
- probe failure verdicts additionally require a resumed lifecycle,
  matching the raster-stall monitor
- linux plugin: deferred-unref grace lengthened to 10s (no raster-side
  completion barrier exists; documented as heuristic), ref bumped

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 12:30:15 +08:00
rustdesk
8fc82d04ac keep lockfile at repo resolution, only bump the two plugin refs
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 11:48:28 +08:00
rustdesk
c6c001a15e bump texture plugins with adversarial-review fixes
flutter_texture_rgba_renderer 7932bf9: linux double-free/terminate-UAF
fixes, exported GetConsumed (was invisible to dlsym under hidden
visibility - the watchdog was silently disabled on Linux), C++14
shared_timed_mutex; macos autoreleasepool + failed-registration guard.
flutter_gpu_texture_renderer 208619e: rendering_ no longer sticks true
before the first populate; honest GetConsumed semantics (descriptor
fetches; EGL bind failure still advances it) - noted at the gpu
watchdog call site.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 11:47:54 +08:00
rustdesk
7da2bbe6ac fix: address texture watchdog/probe review findings
- watchdog: compare the plugin's cumulative consumed counter against a
  snapshot taken when arming (re-arm was a no-op before), and judge on
  cumulative pushes + elapsed time so sparse damage-driven streams are
  still detected
- failure handling is idempotent (one record per breakage) and updates
  every render session like main_set_local_option does, not only the
  failing one; the fallback toast is not claimed for multi-display
  windows the soft path cannot rescue
- probe: skip when the consumed API is missing (old plugin) or a
  raster-stall is recorded (compositing could hang the main window);
  a fail verdict requires fresh frame timings and a non-minimized
  window; a pass never clears failed-raster-stall; toast only when
  texture rendering was effectively on; probe pixel is transparent
- raster-stall monitor: judge on frame-timing staleness (a mid-episode
  hang was undetectable before), gate on lifecycle/minimized/idle with
  a moving quiet anchor, threshold 30s, shared with the camera page;
  clear stateGlobal minimized flag on plain window restore
- adopt mismatched frame sizes only in multi-ui-session mode (legacy
  mode pairs frames loosely and could ping-pong between displays)
- drop the now-dead closeSession parameter from texture destroy();
  trim comments to repo style

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 11:22:13 +08:00
rustdesk
c5adac828b bump hbb_common to merged main (texture-render-health key)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 09:58:31 +08:00
rustdesk
7c23e1f4b9 fix: texture render lifetime protocol, watchdog fallback, startup probe
Root cause of #15848 (and the long-standing macOS #6296 / Linux #3343
class): raw native texture pointers are shared across the platform
thread, the engine raster thread and the video thread, with teardown
ordered by a 100 ms sleep - or, when moving a tab to a new window, by
nothing at all. A lost race frees the texture while it is still in use:
the raster thread parks on a destroyed lock (frozen/black view, a
never-presented 'transparent' hole, every later session black) and the
video thread hangs while holding session locks (app half-dead until
restart, still reported as Responding).

- unregister textures with compare-and-clear (new session_unregister_*
  FFI): a late clear can no longer wipe a new window's registration
  (#8016) and Rust never keeps pushing into a freed texture; the 100 ms
  sleeps are gone (the plugins now drain in-flight pushes and defer
  object deletion until the raster thread is done)
- guard the async texture create path against destroy racing it (#13596)
- per-display locks: the per-frame plugin call no longer holds
  session-level locks, so a stalled plugin or driver call cannot freeze
  every window's UI thread
- adopt the frame size after 30 consecutive mismatches instead of
  dropping frames forever (silent black screen on a live connection)
- watchdog: frames pushed but never consumed by the engine fall the
  session back to software rendering live, record texture-render-health,
  and flip the effective default off; toggling the option clears the
  record and re-arms validation
- Dart raster-stall monitor records a hung raster thread for the next
  launch (rendering cannot be rescued in-process in that state)
- startup probe: render one frame through a 1x1 texture in the main
  window each launch; failure disables texture rendering before the
  first session goes black, a pass self-heals a stale failure record

Platform defaults are unchanged (macOS off, Win10+ on, Linux on).
Requires flutter_texture_rgba_renderer ad4c37e and
flutter_gpu_texture_renderer 767bb9f (pinned in pubspec).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 09:54:17 +08:00
fufesou
c4fd7d692d refact: fuser 0.16.0, cargo 1.75.0 (#15844)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-08-12 21:36:06 +08:00
rustdesk
dfca2c1b8f update agents.md 2026-08-12 17:28:59 +08:00
RustDesk
10bcf976f7 Revert "fix: upgrade fuser to 0.16.0 (GHSA-cvmj-47v9-35m9) (#15834)" (#15841)
This reverts commit 63822048df.
2026-08-12 17:12:46 +08:00
Anupam Mediratta
63822048df fix: upgrade fuser to 0.16.0 (GHSA-cvmj-47v9-35m9) (#15834)
FUSE-Rust: Uninitalized memory read and leak caused by fuser crate
Resolves GHSA-cvmj-47v9-35m9

Signed-off-by: anupamme <mediratta@gmail.com>
2026-08-12 14:30:43 +08:00
fufesou
1d09760ef7 fix(terminal): keep selection aligned after clearing scrollback (#15831)
Remove scrollback lines through the index-aware buffer operation so
deleted anchors are detached and retained lines are reindexed.

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-08-11 15:54:03 +08:00
Chen, Ting-An
23256e6ac1 fix(i18n): complete Traditional Chinese sign-in strings (#15829)
Signed-off-by: 陳廷安 <73953029+nrps9909@users.noreply.github.com>
2026-08-11 14:00:05 +08:00
RustDesk
ff07ff7f13 fix(terminal): send SGR mouse wheel reports with the button codes app… (#15817)
* fix(terminal): send SGR mouse wheel reports with the button codes apps expect

xterm.dart 4.0.0 encodes the wheel buttons as 64+4..64+7 rather than
64+0..64+3, so the low bits land on the modifier field and every wheel
report the terminal emits reads as wheel-with-Shift. Strict full-screen
applications reject the modified event, which is why neither the mouse
wheel nor the trackpad scrolls anything once the peer application takes
over the alternate screen.

Install a mouse handler that keeps every upstream reporting decision and
only re-encodes the wheel buttons as 64..67. Non-wheel reports pass
through untouched, and the emitted bytes stay identical once upstream
ships the same fix, so this can be dropped without a behavior change.

Upstream: TerminalStudio/xterm.dart#238

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(terminal): correct the wheel report row, drop the wasted report build

Address review feedback on the wheel button fix:

- The X10/utf row was encoded as `32 + y + 1` while y is already 1-based, so
  every normal-mode report pointed one row too low and the `y > limit` guard
  disagreed with what it emitted.
- Gate the wheel path on `mouseMode.reportScroll` and the button state instead
  of building and discarding a full report string from `defaultMouseHandler`
  on every scroll tick. This also makes the hardcoded SGR 'M' provably right,
  since a wheel release now returns before the report is built.
- Derive the wire code as `id - 4` and drop `_wheelButtonId`, whose `default`
  branch was unreachable and defeated enum exhaustiveness.
- Assign `mouseHandler` after construction so the `Terminal(...)` line stays
  untouched.

Cover the utf, urxvt, null-byte overflow and click-only branches, and assert
that TerminalModel actually installs the handler.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 13:54:57 +08:00
rustdesk
947cb3f17b propagates the hash-handler continuation result through both connection loops, allowing incoming-only rejection to terminate the connection while preserving existing login flows. 2026-08-10 16:45:27 +08:00
RustDesk
d407db9fae fix(client): allow switch-sides back-connection in incoming-only mode (#15780)
* fix(client): allow switch-sides back-connection in incoming-only mode

"Switch sides" makes the controlled client run `--connect <peer>
--switch_uuid <uuid>`, which Client::_start rejected outright in
incoming-only custom clients, so the feature silently dropped the
session and never switched.

Exempt exactly that back-connection: a default-conn session carrying a
switch uuid may proceed. The uuid is then verified against the local
server process in handle_hash(); if it is missing there (forged or
expired), an incoming-only client now aborts with an error instead of
falling through to password login, so the outgoing-connection
restriction cannot be bypassed with a crafted --switch_uuid.

Fixes rustdesk/rustdesk#11200 (discussion)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(client): validate switch-back grants before connecting

  - check pending peer/UUID grants before bypassing incoming-only mode
  - close rejected switch-back connections and suppress retries
  - keep grant consumption in handle_hash and test non-consuming checks

Signed-off-by: 21pages <sunboeasy@gmail.com>

* fix(client): prevent switch-back UUID reuse

  - claim pending switch-back grants before connecting
  - retain claimed grants to reject duplicate requests
  - bind authorization to the peer ID and UUID
  - use a shared TTL for switch-back grants

Signed-off-by: 21pages <sunboeasy@gmail.com>

* fix(client): defer switch UUID consumption until authentication

Signed-off-by: 21pages <sunboeasy@gmail.com>

* fix(client): reject repeated hash login in incoming-only mode

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: 21pages <sunboeasy@gmail.com>
2026-08-10 16:07:12 +08:00
rustdesk
594e63805c harden login request retry 2026-08-10 16:05:13 +08:00
RustDesk
7c23fd3073 Revert "fix(linux): bound the xrandr call in the wayland primary-display look…" (#15806)
This reverts commit 2915076642.
2026-08-09 18:40:50 +08:00
Mariano Abad
2915076642 fix(linux): bound the xrandr call in the wayland primary-display lookup (#15802)
`try_xrandr_primary` runs a bare `Command::new("xrandr").output()`. Its two
siblings in the same file, `try_kscreen_primary` and the gdbus one, both go through
`run_with_timeout(.., COMMAND_TIMEOUT)`, and the comment above that helper says why:
these commands are known to hang. xrandr is the one left bare.

It matters because of where it runs. `get_primary_monitor` is called from
`get_displays` with the process-wide `DISPLAYS` guard held, and on a Wayland host
the caller can be the service, which has no DISPLAY and no session bus. An X client
that blocks there blocks every consumer of the display list behind the same lock.

No behaviour change when xrandr answers: same command, same parsing, one second of
patience.
2026-08-09 18:04:54 +08:00
lunar-me
11190fa54e docs: fix comma splice gui tutorial in README.md (#15787)
Co-authored-by: pi <pi@m2.local>
2026-08-08 09:33:58 +08:00
lunar-me
d057fe14b2 docs: fix singular contribution in docs/CONTRIBUTING.md (#15789)
Co-authored-by: pi <pi@m2.local>
2026-08-08 09:33:25 +08:00
RustDesk
4234b99029 WebClient: 3.44 webcodecs offline (#15722)
* feat(web): zero-readback WebCodecs video path

Decoded VideoFrames from js/src/webcodecs.js are handed to Flutter via
window.onVideoFrame and imported GPU-side with createImageFromTextureSource;
any failure unregisters the hook so the JS side falls back to RGBA readback.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(web): load bundled terminal font when Google CDNs are unreachable

In air-gapped deployments GoogleFonts.robotoMono() cannot download the
terminal font; when index.html signals offline mode, load the copy bundled
with the web app under the family name google_fonts registers.

Part of the fix for rustdesk/rustdesk-server-pro#996.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci: bump windows arm64 to Flutter 3.44.8, add web build patch script

apply_flutter_3.44_web_patches.sh prepares a 3.44.x web build on top of the
shared source patches: qr_code_scanner's web impl needs dart:ui_web for the
removed platformViewRegistry, and flutter/web/fonts is refreshed to the font
paths the 3.44 engine requests. The disabled build-rustdesk-web job runs it
automatically once FLUTTER_VERSION moves to 3.44.x, and version-guarded
'Patch flutter' steps no longer fail when the guard does not match.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(web): prevent stale WebCodecs frames across sessions

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

* fix(web): harden WebCodecs reconnect and Flutter 3.44 patches

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

* fix(ci): harden Flutter 3.44 patch input validation

Validate required files before checking patch state,
parameterize the theme-range validator, and prevent
missing inputs from satisfying NO_MATCHES checks.

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

* Remove unused code

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

* fix(web): retry font loading and dispose stale decoded images

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

* remove unused code

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

* fix(web): Bad state: RenderBox was not laid out

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: fufesou <linlong1266@gmail.com>
2026-08-07 15:20:57 +08:00
Panos
6fd96dda6e Update Greek translations for various terms (#15782) 2026-08-07 14:39:44 +08:00
Maison da Silva
429c8c6711 Translate sign-in message to Portuguese (#15770)
Translate sign-in message to Portuguese
2026-08-07 08:31:35 +08:00
RustDesk
9a81c8a138 Drm deb in release workflow (#15776)
* docs(agents): add a comment-length rule

Comments were growing to document rejected alternatives, past bugs and
measurements. That belongs in the commit message, not the source.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* ci(drm): build the unattended-wayland deb in the release workflow

The deb was built by a separate drm-capture workflow on a plain runner,
so it diverged from every other Linux deb: different base, different
vcpkg/ffmpeg, different toolchain. Move it into flutter-build.yml as
build-rustdesk-linux-drm, mirroring build-rustdesk-linux's x86_64 path --
same ubuntu18.04 container, same vcpkg install, same rust and flutter.
libdrmtap is built on the runner first and handed to the container via
DRMTAP_PREBUILT_DIR, because bionic's meson is too old to build it.

The job is ungated, so the --drm packaging path is exercised on every PR;
only publishing stays gated on upload-artifact. drm-capture.yml is
deleted along with docs/DRM_CAPTURE_SECURITY.md -- the 29 drm unit tests
that workflow ran are no longer executed by CI.

Three bugs the move exposed:

- build.py anchored the libdrmtap paths on abspath(__file__), which is
  only cwd-independent on Python >= 3.9 (bpo-20443). The packaging
  container runs 3.6 and chdir's into flutter/, so the ABI-gate
  cross-check resolved one directory off and every --drm packaging run
  would have died with FileNotFoundError. Captured as REPO_ROOT at
  import instead.
- DRMTAP_PREBUILT_DIR no longer needs DRMTAP_ALLOW_UNPINNED. A prebuilt
  dir inside the repo's own third_party/libdrmtap at the pinned sha is
  the pinned object, not an override, and is now verified as such.
- The variant's Depends carried a bare libdrm2. libdrmtap needs
  drmModeGetFB2, so it is libdrm2 (>= 2.4.95); below that the package
  installed and could never capture.

The loader also logs the dlerror now instead of discarding it, so a
soname or glibc mismatch is named rather than surfacing as a generic
"libdrmtap not available".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(drm): declare the unattended-wayland deb's real libc6 and libdrm floors

libdrmtap is built on the ubuntu-22.04 runner while the rest of the deb comes
from the ubuntu18.04 container, so the package has a mixed glibc floor and
declared neither half. It installed happily on Ubuntu 20.04 / Debian 11
(glibc 2.31), then dlopen failed on GLIBC_2.34 and capture degraded to the
PipeWire portal -- the one thing this variant exists to avoid. Measure the
floor off the staged objects and put it in Depends, so apt refuses with a
reason instead of handing over a package that can never capture.

Measured rather than written down: the number moves whenever either base does,
and it lands exactly on RHEL/Rocky 9 (glibc 2.34), where one off-by-one decides
whether that whole family can install.

drmModeGetFB2 landed in libdrm 2.4.101, not 2.4.95 -- checked against the
libdrm tags, xf86drmMode.h first declares it in 2.4.101. The old floor admitted
Debian 10 (2.4.97), where the .so is linked -z now and dies on an undefined
symbol at dlopen. libdrmtap's own meson.build carries the same wrong number.

Upload the deb on always(): the run that fails the drm check is the one whose
artifact is most worth downloading. Publish stays gated on success, so an
unverified build still cannot reach a release.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 08:31:09 +08:00
Mariano Abad
ddad47925c feat(linux): DRM/KMS direct capture for Wayland — no portal consent required (#15420)
* feat(drm): opt-in DRM/KMS screen capture for Linux/Wayland

adds an opt-in `drm` feature for unattended remote access on Wayland: it
captures below the compositor via libdrmtap, so there is no
xdg-desktop-portal consent dialog and it works at the login screen.

off by default. when the feature is off the build is byte-identical.
everything is gated behind feature = "drm" or lives only in the separate
rustdesk-unattended-wayland deb, whose package name is the informed consent.

architecture (agreed with the maintainer): the capture runs inside the root
--service, which already holds the privilege it needs, and streams frames to
the user --server over a service-scoped _drm ipc channel. libdrmtap is loaded
with dlopen at runtime (no link-time dependency, so the base build is
unchanged and it still runs on ubuntu 18), and the .so is built in ci from the
rustdesk-org/libdrmtap fork and shipped only in the drm deb. no setcap helper.

- service: DrmReader reads scanout directly via the dlopen loader; an
  IpcDrmCapturer serves _drm consumers with a per-connection capture worker;
  durable availability cache + pre-warm to avoid enumerate/re-probe restarts
- capture: multi-display (targets the selected crtc), hardware cursor over
  _drm, transient-errno retry with a bounded stall, rejects non-32bpp scanouts
  before the frame copy
- robustness: only active, crtc-bound outputs are offered (an unbound
  crtc_id=0 connector is filtered and a client-selected 0 is refused, both
  fall back to pipewire); a per-display rapid-rebuild guard demotes a flapping
  display to pipewire; per-display (not global) zero-frame failure tracking
- root-service hardening: bounded frame allocation and a concurrent-connection
  cap so a malformed scanout or a buggy consumer cannot OOM or thread-exhaust
  the service; a negative availability verdict expires so displays that appear
  after startup recover without a --server restart; exactly-one .so selection
  in the packaging so a stale object is never silently shipped
- build: libdrmtap.so cloned at build time from rustdesk-org/libdrmtap main
  and bundled only for the --drm deb; ci builds a separate
  rustdesk-unattended-wayland deb (incl. an ubuntu 18.04 container)
- DRM_CAPTURE_SECURITY.md: threat model and hardening notes

* feat(drm): phase-2 split, pass the dma-buf fd instead of the converted frame

move the egl detile and rgba pack out of the root --service and into the
unprivileged --server. the root now calls only drmtap_open + drmtap_grab_desc
and exports a raw dma-buf fd; the fd rides the _drm channel over SCM_RIGHTS with
a small descriptor (geometry, per-plane offsets/pitches, modifier, hdr) instead
of the full rgba frame, dropping the per-frame copy. the --server imports the fd
with drmtap_open_render + drmtap_convert_dmabuf, keyed by the import-once egl
cache, and the render context is created and dropped on the recv thread.

the _drm transport moves off Framed<BytesCodec> (which cannot carry a fd) to a
bespoke sendmsg/recvmsg framing (DrmConn) that attaches one SCM_RIGHTS cmsg only
when a fd is present and rejects a truncated ancillary message. the split
symbols are bound optionally so an older libdrmtap still loads the cpu path, and
the whole thing degrades to the cpu BGRA path or PipeWire when no render node is
available. pins libdrmtap-sys to =0.4.13 with the Cargo.lock checksum. folds in
the DP-MST, ldconfig-restart and per-display PipeWire-fallback review fixes and a
udev hotplug refresh.

* drm: address the phase-2 split review

1- do not depend on the libdrmtap-sys crate for the pin: its build.rs statically
compiles the whole libdrmtap C tree and a CAP_SYS_ADMIN helper and links
-ldrm/-lseccomp/-lcap, which defeats the runtime-dlopen model. keep drm a pure
dlopen backend and pin the .so by the build.py DRMTAP_REF release tag, guarded by
a strict vX.Y.Z regex. drops the now-moot Cargo.lock freshness CI checks.
2- render-node-less consumers no longer lose the stream: the --server signals
need_cpu on DrmStart when it cannot open a convert context, and the --service
streams the CPU-converted frame path for that connection instead of a dma-buf fd
the consumer cannot detile (which used to fall through to a PipeWire path nobody
can approve on an unattended seat).
3- mark PipeWire initialized only after every per-display capturer is created, so
a partial failure retries instead of the flag falsely reporting a complete init.
4- reject a degenerate (zero width/height) or short CPU frame before it reaches
PixelBuffer::new (which derives stride as data.len()/height, dividing by zero).
5- keep the export-ledger epoch at DRM_DISPLAY_GENERATION so a hotplug invalidates
cached buffers (elision stays off until the recycled-fb_id inode case is handled).
6- validate the udev uevent source (kernel nl_pid, multicast) with recvmsg so a
local process cannot unicast a spoofed drm-change event to the root listener.

* drm: second review pass on the phase-2 split

1- make PipeWire init atomic: build every per-display capturer into owned staging
first and publish them to CAP_DISPLAY_INFO only after all succeed, so a mid-loop
Capturer::new failure neither leaves partial entries (which the next check_init
would treat as already-initialized) nor leaks the raw pointers already created.
2- pin the immutable libdrmtap commit, not just the tag: git clone --branch
follows a mutable tag, so verify the cloned HEAD equals DRMTAP_SHA in both the CI
workflow and build.py, failing on a moved/compromised tag.
3- drop the stale comment claiming a libdrmtap-sys crate pin (the drm backend has
no such dependency).

* drm: harden the libdrmtap source pin

1- verify the commit-SHA pin on a reused checkout too, not only on a fresh clone:
a stale or mismatched third_party/libdrmtap (e.g. from a failed clone) is now
removed and the build fails instead of silently reusing unpinned source.
2- default DRMTAP_REPO to the fork that actually publishes the pinned tag, so a
clean git clone --branch v0.4.13 resolves (and to the expected commit) instead of
failing on a repo that does not carry the tag.

* ci: make the pinned libdrmtap commit SHA literal

do not let an inherited DRMTAP_SHA override the verified commit in CI, so the
tag/commit pair is immutable there. build.py keeps the env override for local
forks.

* drm: only SHA-verify a git libdrmtap checkout, not a local source tree

gate the commit-SHA pin check on third_party/libdrmtap being a git checkout, so a
clone (fresh, reused, or a stale/failed one) is still verified, but a non-git
source tree a developer placed there on purpose to build unreleased local
libdrmtap is used as-is (it has no tag to verify).

* build: request the libdrmtap shared_library target explicitly

since libdrmtap 0.4.11 the project builds both a shared object and a static
archive, so 'meson compile drmtap' is ambiguous. ask for drmtap:shared_library
(rustdesk dlopens the .so and never links the archive).

* drm: do not reject a non-BGRA scanout on the export side

grab_desc exports the raw scanout dma-buf; the unprivileged converter handles
every format libdrmtap supports (10-bit XR30/AR30 with tone mapping, HDR, CCS)
down to RGBA. The fourcc gate copied from the CPU-mapped grab() wrongly closed
the _drm stream for a 10-bit XR30 primary (0x30335258) that convert_dmabuf
converts fine -- observed live on an i915 seat scanning out XRGB2101010. Keep
the gate only on grab(), whose frame.format is already the converted BGRA.

* drm: do not restart-loop a demoted display PipeWire cannot serve

DRM and PipeWire do not share a display-index space: DRM enumerates one entry
per connector while the portal often exposes a single whole-desktop stream at
index 0. When a per-display DRM capture was demoted to PipeWire for a non-primary
DRM index, cap_map.get(&display_idx) was None and the bail Err made
ServiceTmpl::run retry get_capturer every 1s forever (a multi-monitor restart
loop, latent until a display demotes). Degrade to the whole-desktop stream
(index 0) PipeWire does provide instead of spinning. Healthy DRM displays return
before this and are unaffected.

* ci: build the libdrmtap shared_library target explicitly

the CI .so-prebuild step used the same bare 'drmtap' meson target that is
ambiguous since libdrmtap became both_libraries (0.4.11); ask for
drmtap:shared_library, matching build.py.

* drm: stop altering the stock (drm-off) Wayland path (review 3.2, 4.6)

3.2: get_capturer_for_display no longer falls back to cap_map[0] for a missing
index. CapturerPtr is a bare *mut Capturer cloned by raw-pointer copy, so aliasing
one entry to two display_idx values let two video-service threads call frame() on
the same Recorder unsynchronised (data race / UB), reachable in a plain build via
CaptureDisplays{set:[0,3]}. Restore the exact-index lookup + bail; a demoted DRM
index is dropped from the advertised list at the source instead.
4.6: revert check_init to upstream (flag set before the per-display loop, direct
insert). The staged-all-or-nothing variant turned a partial per-display failure
into a permanent 1Hz retry loop and was not drm-gated. Both restore the drm-off
build to byte-identical with upstream.

* drm: address review findings 3.1, 4.2, 4.3, 4.4, 4.7 + minors

3.1: snapshot the stock flutter bundle before the CI drm relink and restore it
before makepkg, so the official Arch package ships the stock cdylib, not the
drm-enabled one. 4.2: wrap the drm block in a failure-tolerant subshell so a
drm-only failure no longer aborts the stock deb/rpm/arch publish. 4.3: narrow the
publish glob to rustdesk-[0-9]*.deb so the consent-bypass unattended-wayland deb
stays an artifact, not on the public release. 4.4: rewrite the three stale
DRM_CAPTURE_SECURITY.md statements to the split (default path passes a read-only
scanout dma-buf fd over SCM_RIGHTS with an import-once cache; export validation is
metadata-only; BGRA-over-the-wire is the fallback) and document that grab_desc's
fd is O_RDONLY (DRM_RDWR dropped upstream, dup preserves it). 4.7: only
short-circuit to the DRM cursor when it is authoritative (visible, or hidden in a
pure-DRM session); fall through to the normal cursor path in a mixed
DRM+PipeWire session. minors: thread the deb variant by feature not glob; TODO
for the ld.so.conf.d system path; drop a stray blank line. All gated or
whitespace so the drm-off build stays byte-identical.

* drm: re-authorize the _drm stream per frame and auth the producer (review 3.3, 4.1)

3.3: DRM/KMS capture is not session-scoped -- the worker grabs a CRTC's physical
scanout regardless of which session owns the display -- but the peer was
authorized only once at accept. Capture the peer uid and re-check it at the top of
the forward loop: root is always allowed, any other peer must still be the
active-session uid, fail closed otherwise. A session change now tears the stream
down within one frame (~33ms) instead of leaking the incoming user's screen to the
outgoing user's --server.
4.1: connect_drm accepted any producer. Reject a non-root peer (peer_uid != 0) so a
process that won the socket-path race cannot feed the consumer a display list,
frames and dma-buf fds while the DRM path suppresses the portal consent prompt.

* drm: validate cursor body length and coalesce _drm frames to latest-wins (review 4.1, 4.8)

4.1: the DrmCursor consumer handed the wire body straight to the client, which
renders width*height*4 RGBA bytes. Reject a body shorter than that so a truncated
cursor cannot make the client read past the buffer. The hidden-cursor sentinel is
0x0 with an empty body, for which the bound is 0 and the check is a no-op.
4.8: the _drm socket is a FIFO, so a consumer that drains slower than we produce
(a 4K convert on a modest GPU) fell seconds behind stale frames. Drain the producer
channel without blocking each tick and forward only the newest frame; replaced
frames drop in place, closing the zero-copy OwnedFd and freeing the CPU-path pixel
buffer. Cursor updates stay in order and are never coalesced away.

* drm: keep the demoted-display list consistent instead of stretching PipeWire (review 4.5)

A DRM display demoted to PipeWire has no geometry-consistent per-connector stream
on a multi-monitor host -- the portal exposes a single whole-desktop stream. The
fallthrough served that whole-desktop frame while the list still advertised the
demoted connector geometry, so the client stretched the frame and offset all input
by the connector origin (the primary-index-0 demotion reaches this even after the
get_capturer_for_display exact-index fix).

Dropping the display from the list is not an option: its position IS the capturer
index, so a drop would shift every later display and desync get_capturer_info. So
instead: get_display_infos advertises a multi-monitor demoted display OFFLINE at its
stable index, and get_capturer_for_display serves the PipeWire fallback only when
its rect matches the advertised geometry, else bails. A single-display host still
falls through (whole-desktop == that display). All new logic is drm-gated.

* drm: bound the _drm body read, stream-scope cursor teardown, refresh a stale verdict, drop dead clear (review 5)

- recv_msg_timeout2 only gated the wait for the first byte, so a peer that sent one
  byte then stalled pinned the task forever. The same budget now also bounds the body
  read; a body that overruns is a hard error that tears the stream down (recv_msg
  bodies are small JSON, so a healthy peer never trips it).
- The cursor cache is keyed by display index, which a rebuilt stream reuses, so a
  predecessor exiting after its replacement published a fresh cursor erased it. Stamp
  each entry with a monotonic per-stream epoch and compare-and-remove on teardown.
- ProbeState::Available had no TTL, so an idle hotplug left a phantom display in
  enumeration. Give it a timestamp and refresh the list off the hot path once it ages
  past POSITIVE_TTL. The verdict stays true across the refresh (never bounces a live
  session to the portal) and the probe runs on a background thread (never blocks the
  async enumeration).
- Remove the dead clear(): it is unreferenced, and wiring it into teardown would force
  the blocking re-probe on the next enumeration that swap_available_displays exists to
  avoid.

* drm: unit-test the bespoke _drm SCM_RIGHTS framing (review 6)

The _drm wire format is hand-rolled (length prefix plus an fd bound to the frame
first byte) because Framed/BytesCodec cannot carry ancillary data, so it had zero
tests. Add pure-userspace coverage over a socketpair:
- a control message round-trips with and without an attached fd, and the received fd
  refers to the same open file (a byte written into the source is read back through it)
- a raw length-prefixed body (cursor / CPU-fallback path) round-trips byte-for-byte
- a forged length prefix past the JSON cap is rejected at the prefix
- surplus fds packed into one cmsg keep only the first and close the rest
- a control message truncated past DRM_CMSG_CAP is rejected (MSG_CTRUNC), not consumed
- peer_uid_from_fd reads the socket peer credential the producer-auth path relies on

* drm: address the self-review findings on the review rework

Five defects an adversarial pass found in the previous commits:
- refresh_available_async set the single-flight probe guard, then relied on the
  detached thread to clear it; if thread creation failed (EAGAIN) or the closure
  unwound, the guard leaked true and froze every future probe. Release it via RAII
  inside the closure and on a Builder::spawn error.
- The _drm per-frame re-auth called the cached active_uid(), which on a cache miss
  (exactly during a session switch) falls back to a blocking loginctl seat0 lookup --
  on the single-threaded _drm runtime, once per frame, a subprocess storm. Use a new
  cache-only accessor that never blocks and fails closed on a miss, and correct the
  comment: the stop is bounded by the active-uid cache cadence, not one frame.
- set_drm_cursor inserted unconditionally, so a still-draining predecessor stream
  could overwrite (then delete on teardown) the cursor a replacement stream published
  for the same index. Make it a compare-and-set that ignores an older epoch.
- recv_msg_timeout2 treated a spurious readable() wakeup with nothing consumed as a
  mid-frame stall and tore the stream down. Track whether any byte was consumed
  (drm_read_full sets it) and map a zero-progress deadline back to None (re-poll),
  reserving the hard error for a genuine partial-frame stall.

* drm: release the probe single-flight guard via RAII on the cold path too

The cold availability probe in is_available acquired DRM_PROBE_IN_FLIGHT and released
it with a plain store(false) after a synchronous body; a panic there (e.g. a poisoned
DRM_STATE lock) would leak the guard true and freeze both future probes and the
refresh path hardened in the previous commit, since they share the guard. Hoist the
release into a shared ProbeInFlightGuard used by both the cold probe and the refresh
closure, so any exit -- normal, early, or unwinding -- clears it.

* drm: source libdrmtap from rustdesk-org, pinned by sha (review 3.4)

The dlopened .so is loaded into the CAP_SYS_ADMIN root service, so it should come
from the maintainer-owned repo, not a personal fork. rustdesk-org/libdrmtap main is
already synced to the exact commit we pin (c9cf0938 = v0.4.13) but carries no release
tag, so point both build.py and the CI job at rustdesk-org and track main with the
immutable commit pinned via DRMTAP_SHA. The post-clone sha check makes this
fail-closed: main moving off the pinned commit fails the build instead of silently
swapping the .so. The CI ref guard now accepts a vX.Y.Z tag or main (a loose branch is
still rejected). Switch DRMTAP_REF to a tag if rustdesk-org later publishes one.

* drm: dlopen libdrmtap by absolute path + unit-test the _drm admission and re-auth (review 5e, 6a)

5e: the deb dropped /usr/lib/rustdesk into /etc/ld.so.conf.d so the private libdrmtap
could be found by soname -- a system-wide search-path entry that lets it shadow a
system library for every binary on the host, which Debian Policy 10.2 forbids. Resolve
it by absolute path (/usr/lib/rustdesk/libdrmtap.so.0) at the dlopen site instead, with
the bare sonames kept only as a dev fallback, and drop the ld.so.conf.d file and the
ldconfig/try-restart postinst entirely (the .so is present at its absolute path right
after unpack, so the pre-warm resolves with no linker-cache step). The dlopen site is
this PR's own code, so this is in scope, not a follow-up.

6a: extract the _drm admission bound and the per-frame re-auth decision into pure
helpers (drm_conn_admitted, drm_peer_authorized) and unit-test them: admission admits
strictly below MAX_DRM_CONNS and rejects at/above it; re-auth passes root always,
passes a non-root peer only while it equals the active-session uid, and fails closed on
a switched-away, unknown-session, or unknown-peer case. (The /proc/exe-mismatch
rejection is exercised by the accept-time authorize call; unit-testing it in isolation
would need a second process with a different exe, so it stays an integration concern.)

* ci: run the _drm unit tests on every PR (review 6)

The _drm unit tests are behind the opt-in drm feature, which the default workspace
test job does not build, so they would sit in the tree unrun -- no better than no
tests. Add a Linux step to the per-PR ci.yml that runs them with the feature on,
alongside the existing ipc/auth tests. drm is a pure runtime-dlopen backend with no
link-time deps (no libdrm/EGL/gbm) and the tests are pure userspace (socketpair
framing, SCM_RIGHTS, the peer-auth/admission decisions), so this needs no GPU and no
extra system packages. The main build/test stays on default features, so the shipped
drm-off config remains the primary verified one.

* drm: bump the pinned libdrmtap to v0.4.14

Point the DRM capture build at the libdrmtap v0.4.14 release commit
(816766dedaba3140c613712ce97aa2614e8899e7) instead of v0.4.13, in build.py and
the flutter-build workflow, and correct the scrap Cargo.toml note to describe
the actual DRMTAP_SHA anchor. 0.4.14 keeps the same public API, so the dlopen
consumer needs no change.

* drm: address the consumer review (login-screen uid, frame flow control, hotplug)

- Start the login-screen --server as the active seat0 greeter account instead
  of root, so the DRM capture GPU/EGL convert never loads the vendor GPU
  userspace in a privileged process. A genuine root graphical session has no
  lower uid to drop to and stays root, and if the greeter spawn fails we fall
  back to a root --server so the login screen stays remotable. Gated on the drm
  feature so the non-drm build is unchanged.
- Bound the number of frames in flight on the `_drm` channel: the consumer acks
  each frame it finishes converting and the producer only sends while it holds
  credit, waiting on the socket otherwise. Without this the producer kept
  writing descriptors into the socket faster than a slow convert drained them
  and the consumer worked through an ever-growing backlog of stale frames. A
  zero-byte read or write on the ack path is treated as a closed peer rather
  than as success.
- Forward a display list that became empty (last monitor unplugged) instead of
  dropping it, so the availability cache leaves Available rather than keep
  advertising removed displays.
- On a topology change, invalidate the Wayland geometry cache and reapply the
  uinput mouse range for the new layout. The refresh runs off the frame-receive
  loop and is coalesced across the per-display receivers, so a multi-monitor
  hotplug runs one worker and the final layout wins.
- Clear the prefer-CPU-convert hints on a topology change: display indices can
  be renumbered, so a hint learned for an old index no longer refers to the same
  physical display. Re-learned on the next convert failure.
- Report a non-DRM-backed display when the DRM list is shorter than the sync
  list or any entry is offline, covering the present-but-demoted case.

* drm: log why the uinput refresh worker could not start

The worker released its coalescing slot and returned silently when the runtime
failed to build, leaving the uinput range stale for the new layout with nothing
in the log to explain it.

* drm: gate only frames on send credit, never cursor or topology updates

The credit check sat at the top of the producer loop and continued on exhaustion,
so while a slow convert withheld its ack the loop never reached the code that
forwards cursor updates and pushes a changed display list: the remote cursor
froze and a hotplug went unreported until credit returned. The comment claimed
those were not credit-gated; structurally they were.

The loop now always receives and processes producer messages. Only the frame send
is gated: when credit is exhausted the newest frame is held back (latest-wins,
matching the existing coalescing) and flushed as soon as an ack lands, while
cursors and the topology push go out unimpeded. While a frame is held the loop
also waits on the socket, so an ack wakes it promptly rather than only when the
next frame arrives; both select arms are cancel-safe.

* drm: fix three defects in the frame credit gate

Follow-up to the previous commit, from an adversarial review of it.

- The ack wake-up skipped the coalescing drain. When the socket arm of the
  select won, there was no message to seed the drain loop with, so the channel
  was never polled that iteration: a held frame could be sent while a strictly
  newer one already sat queued, and a queued cursor waited for the next producer
  message. Seed the loop from the channel when we woke on an ack instead.
- The loop could wait while holding a frame it was allowed to send. Credit
  replenished by the top-of-loop drain was not consulted before entering the
  select, so the frame waited for the worker's next message; if capture then
  returned WouldBlock it sat there until the stall teardown. Take whatever is
  queued without blocking in that case and fall through to the send.
- The capture worker no longer had any backpressure. Draining the channel every
  iteration (needed so cursors keep flowing) means a full channel no longer
  parks it, so a consumer converting at a fraction of the capture rate made the
  privileged service keep grabbing frames that were then discarded -- a packed
  copy per frame on the CPU path, a PRIME export on the dma-buf path. The worker
  now skips the grab while the task is holding an undeliverable frame, and keeps
  polling the cursor so the remote pointer stays live. The gate is deliberately
  conditioned on holding a frame, not merely on having no credit: with nothing
  held the task blocks in recv() and cannot observe an ack, so gating there
  would stop the worker feeding it at all.

The comment claiming the bounded channel backpressures the worker is corrected.

* drm: gate capture on credit alone, and bound the no-credit wait

Follow-up to the previous commit, from an adversarial review that modelled the
loop with a real runtime, socket pair and worker thread.

Gating the worker only while a frame was already held was wrong: those grabs are
not wasted work, they keep the held frame fresh, because the coalescing below
lets each newer frame supersede it. Pinning the worker at that moment therefore
froze whatever frame happened to be in hand when credit ran out and shipped it
stale once the ack landed -- measured at ~91ms average staleness against ~2ms
with no gate at all. Gating on lack of credit alone, and waiting on the socket
whenever credit is out rather than only while holding a frame, keeps the CPU
saving (the worker still stops grabbing) with no staleness: the ack resumes the
worker and what goes out is a fresh grab. Modelled at 0ms staleness and the same
delivered-frame count, with 31 grabs versus 588 ungated. It is deadlock-free
because the socket is watched in exactly the states where the gate is set.

The no-credit wait is now bounded (5s). While gated the worker does not grab, so
it cannot advance its own MAX_STALLED watchdog; a consumer that stopped acking
without closing the socket could otherwise hold this connection, its worker
thread and the privileged DRM context open indefinitely.

* drm: measure the no-credit deadline from the last ack, not the last wake-up

The bound added in the previous commit was a timeout on the wait itself, so any
wake renewed it -- and cursor messages keep arriving while frames are gated, so
a consumer that had stopped acking but still moved its pointer would renew the
deadline forever and never be torn down. Track when we last held credit instead
and enforce the deadline against that, keeping the wait capped only so we still
wake to re-evaluate it when nothing arrives at all.

* drm: drop to Unavailable when the background refresh finds no displays

The review asked for two things when the last CRTC disappears: push the empty
topology to consumers, and stop advertising the removed displays. Only the first
was done. The positive-TTL refresh still discarded an empty probe result and kept
the previous list, so on an idle host -- where there is no live stream to carry
the hotplug push -- enumeration kept reporting displays that were gone, exactly
as described. It now transitions to Unavailable on an empty result, matching the
hotplug path, while a failed probe (transient open/EACCES, not evidence the
displays are gone) keeps the verdict and only restamps it.

* drm: do not let a stale availability probe overwrite a newer verdict

query_displays() in the background refresh runs unlocked because it is slow, so
a hotplug push can publish a newer verdict while it is in flight; the refresh
then overwrote it with its own older result. Harmless while it only replaced the
list, but the previous commit made an empty result drop to Unavailable, so a
probe that started while the monitors were gone could disable DRM on a host
whose monitor had since come back.

The refresh now samples the stamp of the verdict it is refreshing and publishes
only if that stamp is still current. Every publish stamps a fresh Instant, so an
unchanged stamp means nothing republished in between -- equivalent to threading a
revision counter through every publish site, without having to keep all of them
in sync.

* drm: track availability publishes with a generation, and hold the probe guard across the whole path

Two defects in the previous commit's staleness check.

The single-flight guard was still created inside the spawned closure, but that
commit added a DRM_STATE lock before the spawn. A poisoned lock there would
unwind past the flag with nothing to clear it, leaving DRM_PROBE_IN_FLIGHT set
and freezing every future probe. The guard is now taken immediately after the
flag is acquired and moved into the closure, so it covers the lock, the probe,
and a failed spawn alike. The explicit release on spawn failure is gone with it:
it was not merely redundant but wrong, since by then another refresh may have
acquired the flag and clearing it would let two probes run at once.

The staleness check itself compared Instant stamps, which made correctness
depend on an implicit invariant -- that every publish restamps -- spread across
ten call sites; a future publish that reused a stamp would defeat it silently.
DRM_STATE now carries an explicit generation, bumped by publish_probe_state,
which every write to the state goes through. Instants are left to serve only the
TTL checks. The failed-probe branch deliberately restamps without bumping: it
touches the TTL, not the verdict, so a concurrent probe loses nothing by
publishing over it.

* drm: convert each display on the GPU that exports it

The unprivileged converter opened its render context with
drmtap_open_render(NULL), letting libdrmtap auto-select. On a multi-GPU host
that can land on a different GPU than the one driving the display, and importing
a scanout across vendors can fail permanently on an incompatible tiling
modifier.

The service already knows the exporting device, so it now names its render node
(drmtap_render_node, libdrmtap 0.4.15) in each DrmDisplayInfo, and the consumer
opens the converter on that node. The field is serde(default) and empty means
auto-select, so a service and a server from mismatched builds still interoperate
and a pre-0.4.15 .so degrades to exactly the previous behaviour. The path is
realpath-gated to /dev/dri before it is opened, the same gate the capture device
gets, since it arrives over IPC. When the named node cannot be opened the
converter returns None and the existing need_cpu fallback runs the convert on the
exporting GPU service-side, which is the most correct place for it anyway.

Added a wire-compat test that a pre-render_node DrmDisplayInfo payload still
decodes (empty node) and a current one round-trips the node.

* drm: advertise the displays of every GPU, not just the first card

A drmtap context is bound to a single DRM device, so the service enumerated one
auto-detected card and advertised only its monitors. On a multi-GPU host every
display driven by another card was invisible to the client, and its card-local
CRTC id could not have been opened through the wrong device anyway.

The service now enumerates every card (drmtap_list_devices, libdrmtap 0.4.15),
opens one reader per device, and merges their displays into the one list, each
tagged with its own card node and render node. DrmStart resolves the chosen
index to that display's device + CRTC and the worker reopens the right card;
the converter already binds the display's render node. Both new fields are
serde(default) and empty means the single auto-detected device, so a pre-0.4.15
.so and a mismatched-build peer keep the previous behaviour exactly.

Enumeration replaces the single-reader open in the pre-warm, the udev hotplug
refresh, and the per-connection handshake, so a hotplug on any card is picked up
and an all-monitors-off state now correctly publishes an empty list. The
per-connection cache refresh re-enumerates all cards rather than only the
connection's device, so serving one display never drops the others from the
next handshake.

Verified on a Jetson Orin (its two DRM devices, only card2 driving a display):
list_devices reports card2/renderD129 with one display, enumeration produces
exactly that display tagged to card2, and card1 (no active CRTC) is skipped -
no phantom, no regression on the single-display case.

* drm: bump the pinned libdrmtap to v0.4.15

* drm: do not guess the exporting GPU when the host has several render nodes

The converter binds the render node the service names for a display, and falls
back to auto-selection when that name is empty. An empty name is what an older
libdrmtap produces: the service resolves it with drmtap_render_node, which only
exists since 0.4.15, and rustdesk dlopens libdrmtap.so.0 by soname, so the
runtime library can be older than the one the build was pinned to.

Auto-selecting is not safe there. On a single-SoC multi-device host the wrong
choice does not fail: a Jetson Orin exports the scanout from nvidia-drm while
the first render node belongs to tegra, and importing the scanout on the tegra
node SUCCEEDS and yields corrupted pixels. There is no convert error, so the
prefer-cpu bit never learns anything and the stream simply looks broken with a
clean log.

Request the CPU-converted path instead whenever the exporter is unnamed and the
host exposes more than one render node: the service converts on the device it
already has open, which is correct by construction. Hosts with a single render
node have nothing to pick wrong and keep the dma-buf path untouched.

Verified on a Jetson Orin Nano, the two-device host: with a libdrmtap that
lacks drmtap_render_node the capture used to come through visibly corrupted,
and now falls back to the cpu path and renders correctly. With 0.4.15 the
service names renderD129 and the dma-buf path is used as before.

* drm: name the libdrmtap that was really loaded, and say so when it is stale

Two hours went into a corrupted capture whose only symptom was a clean log
saying "libdrmtap loaded: /usr/lib/rustdesk/libdrmtap.so.0 (v0.4.15)". The
library behind that soname symlink was a pre-release 0.4.15 that reported the
version but did not export drmtap_render_node, so the service silently stopped
naming the exporting GPU. The log named the symlink it asked for, which is not
evidence of anything, and the version it printed came from the library itself,
which was the part that lied.

Log the file the absolute candidate actually resolves to, and warn when a
library reports 0.4.15 or newer while missing drmtap_render_node or
drmtap_list_devices, naming that file: a version that claims features the
symbols do not back means a stale or pre-release build, and the effect is
invisible otherwise. Only the absolute candidate is resolved, because dlopen
does not search the process CWD for a bare soname while canonicalize would.

Also correct two places that no longer matched the code: the security document
still described an /etc/ld.so.conf.d drop-in and an ldconfig trigger that
build.py deliberately does not ship (the .so is dlopened by absolute path and
the package makes the soname symlink itself), and the comment above the render
node lookup still said an unnamed exporter always falls back to auto-selection.

* drm: tighten the render-node count and the loader diagnostics

Four corrections from a review pass over the previous two commits.

Count only a render node whose name is renderD followed by a numeric minor.
The prefix test also matched something like renderD.backup, which would have
inflated the count and pushed a genuinely single-GPU host onto the CPU path.

Log the load only after every required symbol resolved. load() still returns
None when one is missing, so announcing success first could print "libdrmtap
loaded" and then "libdrmtap not available" for the same library.

Name only the capability each absent symbol costs: a library missing just
drmtap_render_node loses exporting-GPU selection, one missing just
drmtap_list_devices loses multi-GPU enumeration, and the previous wording
claimed both were gone in either case.

Fix the security document's audit step. The dlopen names the symlink by
absolute path and the package registers no linker directory, so a leftover
object beside it is not loaded on its own; what matters is where the symlink
points, and a leftover only matters as what a stray ldconfig would repoint it
to. Ask the auditor to read the symlink target instead.

* docs: list every case that selects the CPU-converted frame path

The security document described the CPU fallback without saying when it is
taken, and the multi-GPU safety fallback added in this branch was not mentioned
at all. Enumerate the four cases, including the one where the service could not
name the exporting GPU on a host with several render nodes, and note that a
single-render-node host keeps the DMA-BUF path.

* drm: fetch libdrmtap by commit sha instead of cloning a branch

`git clone --depth 1 --branch main` fetches only the tip of that branch, so the
moment upstream pushes to libdrmtap `main` the pinned commit is no longer present
in the shallow clone at all: the build fails on an unreachable object rather than
on a mismatched pin, and it fails for a reason that has nothing to do with the
checkout being wrong. In the release workflow the whole block is wrapped so the
job stays green, which means the drm deb would simply stop being produced without
anyone noticing.

Fetch the sha directly instead. No branch or tag name takes part in the build now,
so it survives every upstream push and cannot be affected by a ref being moved or
repointed. DRMTAP_REF is gone, along with the regex that validated it.

The post-fetch sha check stays, with a narrower job: a fetch by sha cannot resolve
to anything else, so it now guards a reused checkout left at a different pin, which
is exactly what a version bump leaves behind. It still removes that tree so the
next run re-fetches cleanly.

build.py is now the single source of truth for the pin.

* drm: move the drm CI out of the stock workflow, and stop touching scrap/Cargo.toml

The instruction was that nothing outside the feature should change while the
feature is off, and the runtime code honors that, but the build plumbing did not.
Start undoing that.

ci.yml goes back to upstream byte for byte. The drm test step it carried now lives
in a new workflow that only fires when a drm path changes, so a PR that does not
touch this backend pays nothing for it.

That new workflow also runs the whole rustdesk-crate test set with the feature on
rather than filtering by the `_drm` test names, because the name filter skipped
the sibling assertion that bounds `size_of::<Data>()`, which the new DmabufDesc
variant grows.

It gains a second job that fetches libdrmtap at the pinned commit, builds the .so
and then asserts the contract the runtime depends on: every symbol the loader
resolves, derived from the loader source so the two cannot drift, plus evidence
that the EGL detile path is really compiled in. libdrmtap degrades to a CPU-only
stub when the egl/glesv2 pkg-config files are absent on a build host, and nothing
downstream noticed. Note the check looks for the dlopen target name and the import
call, not for DT_NEEDED: EGL is loaded lazily on purpose so the privileged process
never links the vendor GL stack, so an ELF-level check reports a false negative on
a correct library.

libs/scrap/Cargo.toml keeps only the added feature: the unrelated blank line before
[dependencies.hwcodec] is restored, and the comment no longer describes DRMTAP_REF,
which no longer exists. The feature is now drm = ["wayland"] because all three drm
modules live inside the wayland arm of common/mod.rs, so scrap/drm alone compiled
nothing; it worked only because the root crate always enables scrap/wayland.

* drm: build the unattended-wayland deb in its own workflow, not in the release job

flutter-build.yml goes back to upstream byte for byte. Three separate changes to
the stock release path disappear with it: the drm variant built inside the release
container, the snapshot and restore of the stock flutter bundle that existed only
to keep the drm relink out of the archlinux package, and the narrowing of the
publish glob to keep the consent-free deb off the public release.

The deb now builds in the drm workflow instead, which also removes the failure
mode the old placement forced: the whole block had to run in a subshell ending in
`|| echo WARN` so a drm-only breakage could not abort the stock publish steps,
which meant every failure in it, from the fetch to meson to packaging, kept the
job green and silently stopped producing the deb. A separate job can just fail.

The bridge generator is a reusable workflow, so this calls the stock one rather
than duplicating the codegen.

The deb is asserted rather than trusted: build.py can exit 0 without producing a
package, so the job checks the file exists and that it carries both the real
libdrmtap object and its soname symlink. It stays an artifact and never a release
deliverable, and it is built on the runner rather than in the old container the
stock debs use, so its glibc floor is higher than a released package.

* drm: stop refactoring the shared packaging path in build.py

generate_control_file goes back to upstream byte for byte: no extra parameters, no
conditional inside it. The variant instead rewrites the control file that function
just produced, so everything specific to the consent-free package lives in added
code rather than in the shared one. That rewrite fails loudly if either anchor line
stops matching, so a future upstream change to the control layout cannot quietly
yield a variant deb wearing the stock package name.

finalize_deb is gone. It had pulled the tail of both deb builders into one shared
helper, which is a refactor of a path the feature has no business touching. Both
builders now carry their upstream tail verbatim, with the drm work added as three
guarded blocks: stage the library, retarget the control, rename the output. With
the feature off, every line is upstream's.

Verified rather than argued, by building both packages with this script:
the drm deb is Package: rustdesk-unattended-wayland, carries Conflicts, Replaces
and Provides on rustdesk, has libdrm2, libegl1 and libgles2 appended to Depends,
and ships libdrmtap.so.0.4.15 plus its soname symlink. The stock deb is
Package: rustdesk, carries none of those three fields, and contains no libdrmtap
file at all.

* drm: key per-display state by connector identity, and end a stream whose index moved

The service binds a stream to (device, crtc_id), which survives a topology change.
Everything on the consumer side addressed it by list index, which does not:
drm_enumerate_all_displays concatenates per-card lists, so plugging or unplugging a
monitor renumbers every display after it. Two consequences, one live and one
remembered.

Live: a running stream kept sending monitor A while the advertised list, and so the
client layout and the injected-input rect, had come to mean monitor B. It only
resolved if the stream happened to fail on its own. The stream now records what it
was bound to and ends itself when its index stops meaning that, which routes the
change through the rebuild the video service already does.

Remembered: the zero-frame failure counts and the prefer-cpu verdicts were keyed by
index too, so after a renumbering one monitor could inherit another's demotion or be
forced onto the CPU convert path for a mismatch that was never its own. Both are now
keyed by device plus connector name. The reasoning was already written down for one
of these, in the comment above the prefer-cpu clear, and applied only there.

That bulk clear is gone with it. It existed to limit the damage of index aliasing;
with identity keys it would instead throw away a correct verdict, which costs a real
convert failure to relearn, on every unrelated hotplug.

Also fixes the drm workflow to skip the two tests the stock CI already skips. Both
need a display server and fail on any headless runner, so the job would have gone
red for a reason that has nothing to do with this feature. Verified by running the
exact command: 88 tests, including the size_of::<Data>() assertion that the old
name filter was hiding.

* drm: end the session when the captured display changes geometry mid-stream

A resolution DECREASE wedged the stream. The encoder is sized once, from
CapturerInfo at capturer build time; check_display_changed returns None on Wayland,
so the periodic display-changed broadcast never fires there; and convert_to_yuv only
bails when the source is LARGER than the destination. A smaller frame therefore
passed all three and was encoded into the previous canvas, leaving stale content
along the right and bottom edges for the rest of the connection. An increase
recovered only by accident, because convert then refused and the service rebuilt.

This is ours to contain rather than merely inherited: the DrmDisplaysChanged
handler re-broadcasts the new geometry through SYNC_DISPLAYS, so the client layout
and the pixels it receives actively disagree, where before there was no topology
signal at all.

The capturer now records the geometry its session was built with and returns a hard
error from frame() when a dequeued frame differs, which routes a shrink through the
same rebuild an enlargement already takes. got_frame is set first so a session that
did deliver frames is not counted as one of the zero-frame sessions that demote a
display to PipeWire.

The general fix belongs to the Wayland path rather than to this backend, and is
filed separately as #15695.

Four tests cover it, the first in this file: the matching size is delivered, a
smaller and a larger frame both end the session, and an unknown session size stays
out of the way instead of rejecting everything.

* drm: refuse a libdrmtap that cannot do the split export

The root --service must never load libEGL/libGLESv2: the point of the split is
that it exports the scanout dma-buf and the unprivileged --server converts. Two
paths could still break that, both because the loader accepted a library too
old to export.

drm_prewarm() called grab() when the loaded .so had no drmtap_grab_desc, and
grab() maps and detiles, so the privileged process pulled in the vendor GL stack
at startup, before any consumer had asked for a frame. The per-connection
capture loop then did the same for every frame, through the CPU fallback.

The version guard could not prevent it: it compared the ABI major only, and this
library is still 0.x, so every release it has ever made passed. Add a floor at
0.4.9, where the split entry points landed, and require the three split symbols,
which also rejects a build that reports a new enough version without carrying
them. That is not hypothetical: a pre-release stamped 0.4.15 shipped without the
multi-GPU accessors. Both refusals fall back to PipeWire/portal and say which
file and which symbols, at warn level.

The split symbols are no longer Options, so the type system carries the
guarantee instead of a convention. What is left of the CPU path is only what it
was meant to be: the consumer has no render node of its own, or the seat exports
no transferable dma-buf. Both are facts about the hardware, with no alternative
that keeps the stream, and neither is a property of which file was on the load
path.

Verified against the real library on i915. With 0.4.15 the export path captures
a tiled XR30 scanout and libEGL stays out of /proc/self/maps, while the old
grab() branch maps it, so the finding reproduces. A stub reporting 0.4.8 and a
stub reporting 0.4.15 without the split symbols are both refused, each with its
own diagnostic. The mirrored repr(C) layouts are unchanged across 0.4.9 to
0.4.15, checked field by field against include/drmtap.h at both ends, so the
floor costs no compatibility that was real.

* drm: move the _drm channel and its producer into src/ipc/drm.rs

src/ipc.rs is the file every unrelated IPC change has to be read through, and
this branch had grown it from 2227 lines to 4112. Move the DRM half out, into
the same #[path] submodule form the file already uses for ipc/auth.rs and
ipc/fs.rs, so it lands as ipc/drm.rs beside them.

What moves: the two payload structs, the producer that runs in the root
--service, and the bespoke SCM_RIGHTS framing the channel needs because
Framed/BytesCodec cannot carry ancillary data, plus their tests. What stays is
the Data variants, which belong to a shared enum and cannot live anywhere else,
and three re-exports so every existing call site keeps the path it already uses.

ipc.rs is 2285 lines now, 58 above upstream instead of 1885. The move is
content-identical: the only edits are the 39 per-item cfg attributes, redundant
now that the module is gated once at its declaration, and the test module cfg
that becomes a plain cfg(test). Checked by extracting the moved ranges from the
previous commit and comparing them line by line against the new file. Both
configs build with no new warnings and the same 92 tests pass, 14 of them the
drm ones that moved.

* drm: bound the _drm accept path (M1, M2, M8)

M1: authorization is now done on the blocking pool. It reads the active session
uid, which on a cache miss forks loginctl, and the socket is 0666 so any local
uid can make us do it. The same call exists for _service, but this runtime is
shared by every live capture stream, so a stall here hitches frames instead of
delaying one config sync.

M2: the handshake was a loop that ignored unexpected messages, which restarted
the ten second budget on each one, so a peer sending junk just inside the timeout
held a worker thread and one of the eight connection slots for as long as it
liked, and eight of them denied DRM capture entirely. It is one receive now, and
anything that is not DrmStart closes the connection: the consumer answers the
display list with DrmStart and nothing else, so there is nothing legitimate to
skip past.

M8: dropped the extra unauthorized-connection warn. log_rejected_service_connection
inside the authorization already logs the rejection with the peer and active uid
and rate limits it to one line per five seconds, which is exactly what a
world-connectable socket needs; the second line had no throttle and handed anyone
who can connect an unbounded log write.

Both configs build, 92 tests pass.

* drm: stop the two states that never settle (M4, M6)

M4: a dead producer left the availability verdict positive forever. The
background refresh keeps a positive verdict on a failed probe, which is right for
one failure and wrong for a run of them: if the root --service dies while this
--server lives, every probe fails, the cached list keeps being advertised, and
every display restart-loops. Three consecutive failures now drop the verdict to
Unknown, not to Unavailable, because the evidence is about the producer and not
about the hardware, so the next enumeration probes from scratch. The cold probe
also resets its own failure budget on success: it was never reset, so the five
strike allowance was spent once per process and a later probe demoted on its
first failure.

M6: a display that can never be grabbed churned PeerInfo about every 35 seconds
for the life of the process, because the cooldown was flat: demote, wait 30 s,
get advertised online, burn four sessions in a few seconds, demote again. The
cooldown now doubles per demote cycle up to 8 minutes. Recovery is unchanged in
the way that matters, since the count is erased the moment the display delivers a
frame rather than decaying with time, so a monitor that comes back is served
immediately.

Also, while changing that map: a zero-frame session on a display with no
connector identity was recorded under the empty key, which is the same aliasing
H2 removed for indexes, one unidentifiable display would have demoted the next
one. It is skipped now, as the comment above it always claimed.

Two new tests cover the backoff schedule and the reported 35 second cycle. 94
tests pass, both configs build.

* drm: give the DRM uinput update the timeout and the bookkeeping (M3, M6)

The DRM path sets the uinput absolute range itself, because it bypasses
check_init. That copy awaited update_mouse_resolution raw, and it was missing
three things check_init has sixty lines above it.

No timeout: uinput set_resolution reads its reply with no timeout of its own, so
a hung uinput socket blocked every video-service start on this branch, and wedged
the hotplug worker inside rt.block_on with UINPUT_REFRESH_BUSY latched true,
after which every later hotplug refresh was silently skipped for the process
lifetime. It is bounded at 3 s now, the same bound check_init uses.

No bookkeeping: it never called set_wayland_uinput_rect or
set_wayland_layout_baseline, which is why the #15601 layout-drift remap never
activated on the DRM path. Both are recorded now, and only after a successful
apply, so a transient failure is retried rather than remembered as applied.

No cache invalidation: the cached Wayland layout can predate compositor changes
made while no session was active, which is the case #15601 is about. Dropped
first, as check_init does.

It also stops reprogramming the device when the range has not changed (M6): a
display in a rebuild loop called this about once a second, and reapplying an
identical range is an IPC roundtrip plus a uinput reconfiguration under a user who
may be at the console. The layout baseline is still re-snapshotted on every call,
since it is what the client coordinates are measured against.

Left as a separate copy rather than folded into check_init: check_init ships in
every Linux build and the standing rule for this feature is that the drm-off
build does not change by a line. Both configs build, 94 tests pass.

* drm: check the greeter server is alive, not just spawned (M5, M10)

M5: the greeter fallback tested the wrong thing. start_server reports whether the
SPAWN succeeded, so a greeter account that cannot actually run the server, a
nologin shell or a hardened home, leaves a child that exits at once; the loop
sees only that the child is gone and respawns it as the greeter forever, never
reaching the root fallback, and the login screen becomes un-remotable on a host
where it used to work. It now requires the child to still be alive after a one
second grace before accepting it. A server that dies later than that is a
different, transient failure and the existing restart throttle already bounds it.

While there: the whole greeter branch is now inside the drm cfg, so the drm-off
build is upstream's single start_server line again rather than a run_as_greeter
variable that is always false.

M10: two monitors of the same model and resolution whose names do not normalize
to the compositor's matched no output at all, so both kept the DRM origin, which
is (0,0) for independent CRTCs. The client stacks them and injected coordinates
hit the wrong monitor with certainty. Unmatched connectors now take the next free
output in layout order, preferring one of the same physical size, and say so in
the log. That is at worst a swap of two identically sized rectangles, and the
layout stays coherent. The same pass also stops one output being claimed by two
connectors, which the unique-resolution rule allowed.

The assignment is now a pure function, so the cases are testable without a
compositor: five tests cover the naming difference, the identical-monitor case,
the double claim, name match beating the fallback, and more connectors than
outputs. 99 tests pass, both configs build.

* drm: stop reallocating and recopying whole frames (M9)

The CPU fallback moved a scanout four times: the producer packed it, the kernel
carried it, next_raw allocated and zeroed a fresh buffer to read it into, and the
consumer copied that into the slot. At 4K30 the last two are about 8 GB/s of
memory traffic that does nothing.

next_raw_into reads the body straight into a buffer the caller owns, so the
kernel copy lands where the frame is going to live, and resize costs nothing once
a buffer has seen one frame of that size. The frame buffers then circulate
instead of being freed and reallocated: whatever a new frame displaces goes back
on offer, both when the encoder consumes one and when a frame is superseded
before anyone reads it. The dma-buf path still copies once, because the convert
output is borrowed from the render context and only lives until the next convert,
but it copies into a recycled buffer and does it outside the slot lock, so a
multi-megabyte memcpy no longer holds the encoder off the slot.

Steady state is now one allocation for the whole session on both paths, and the
CPU path carries the pixels twice instead of four times.

The cursor body reads into its own buffer and is moved into the cursor cache
rather than copied; it is small and rare, so it stays out of the frame recycler.

Two tests: the raw body round trip now also covers a shorter body reusing the
buffer, so a stale tail cannot survive into it, and a new test asserts the frame
buffers circulate by allocation identity rather than by inspection. 100 tests
pass, both configs build.

* drm: the polish list, and a correction to my own ABI floor

The version floor I added two commits ago was one release too low.
drmtap_open_render and drmtap_convert_dmabuf are 0.4.9, but drmtap_grab_desc is
0.4.10, so a genuine 0.4.9 library passed the version gate and was then refused
by the symbol gate with a message that called it a stale or pre-release build,
which it is not. The floor is 0.4.10 now, the release where the whole split API
exists, and the test lists 0.4.9 among the rejected versions with the reason.

ExportLedger is deleted. DRM_FD_ELISION was false, so should_send_fd returned
true at its first branch and about sixty lines of eviction and epoch machinery
were unreachable, untested, in a security sensitive file. Why it was disabled
is worth keeping, so here it is: eliding the fd on an fb_id the converter has
already imported looks free, but the kernel can recycle an fb_id onto a
different buffer with identical geometry and modifier, and the exporter cannot
see the dma-buf inode that would tell the difference, so the elision can serve
a stale EGLImage. Sending it is cheap, the converter imports once per buffer and
closes the surplus fd, and libdrmtap's own cache keys on fb_id AND inode and can
only re-import when it is handed a real fd. That reasoning now lives here
instead of in dead code.

The rest:

- num_planes is clamped on the consumer before it reaches the C descriptor. The
  producer normalizes it and must be root, so this is only defense in depth, but
  the wire is the one place the value arrives from another process.
- warm_availability returns early on X11. Nothing there can consume a DRM
  stream, and probing makes the ROOT service open DRM readers, so an X11 host
  running a drm build was paying that at every startup for a path it can never
  take.
- drm_cursor_id no longer clones the cursor. The cursor service polls it at
  frame cadence to compare eight bytes, and a 256x256 cursor is 256 KiB.
- The premultiplied ARGB pass-through is now documented as matching the XFixes
  path, since that is why it is correct rather than an oversight.
- cfg hygiene: input_service.rs uses all(target_os = "linux", feature = "drm")
  like every other site, and active_uid_cached is gated with the feature too,
  which also removes a dead-code warning from drm-off Linux builds.
- Nits: DrmConn is pub(crate) like its constructors, new_drm_listener is no
  longer async with nothing to await, and the two anyhow! plus return Err pairs
  are bail! as the codebase writes them.
- DRM_CAPTURE_SECURITY.md moves to docs/ with the other docs, and its "no
  privileged child process is ever spawned" claim is corrected: an empty
  helper_path is not a disable switch in the C, find_helper searches six fixed
  paths and would exec one if the direct export ever failed. It is unreachable
  here for two independent reasons, the root service holds CAP_SYS_ADMIN so the
  direct path succeeds and the package builds no helper at all, and the paths
  are root-writable only, so the accurate statement is that this package never
  installs one, not that it can never happen.
- The comments that narrated the review rather than the code are rewritten to
  say what the code does. One of them had also drifted: the convert context is
  opened before we answer with DrmStart, not before the handshake.

Both configs build with no new warnings, 100 tests pass.

* drm: one DisplayHealth per connector, and the last index-keyed map

The three per-display verdicts are three answers to one question, can this
display be captured over DRM right now, and they already fed each other: the
rebuild cadence and the zero-frame streak end in the same demotion, and the
convert verdict is what keeps a multi-GPU display off the dma-buf path so it
never gets there. They are one struct now, keyed by connector identity.

This also closes a real leftover from H2. Two of the three maps were re-keyed by
identity then; the rapid-rebuild map was not, and stayed keyed by list index. A
hotplug that renumbers the list therefore moved a flap verdict onto whichever
monitor took that slot, which is the same defect in the third map. There is no
index-keyed per-display state left.

Behaviour is otherwise the same, with one improvement that falls out of the
merge: when a demotion cooldown expires, clearing the streak now keeps the
display's other state rather than replacing the whole entry, so a build cadence
and a convert verdict survive a retry the way they always should have.

One test for the demoted predicate, including that a higher demote count still
holds a display that a lower one would have released. 101 tests pass, both
configs build.

* drm: bound the GITHUB_TOKEN in the drm workflow

CodeQL flagged the new workflow for not declaring permissions, which is fair:
every job here only checks out, builds and tests, and the artifact up/download
in the deb job authenticates with the runtime token rather than this one, so
contents: read is the whole requirement. Declared at the workflow level so the
reusable bridge workflow it calls inherits the same bound.

The stock workflows do not declare it either, but they are upstream's and this
feature does not touch them; a new file can start out right.

* drm: make the outer handshake budget dominate the inner one

Two findings from the review bot on our own fork, both worth taking.

The caller waited HANDSHAKE_TIMEOUT_MS + 500 for the receive thread to hand back
the display list, but that thread is allowed to spend more than that: the connect
budget, and then recv_msg_timeout2 applies its argument twice in the worst case,
once waiting for the first byte and once for the body. So on a slow connect the
outer timer fired first and abandoned a handshake that was still inside its own
budget. The wait is now derived from those parts rather than written as a
constant, so changing either one cannot silently invert the relationship again,
and the two connect sites use the named constant instead of a literal.

The cursor cache insert shadowed hcursor under a cfg, so the same line meant the
requested id in one build and the served id in the other. It is a separate name
now, with the reason on it.

Not taken, and why: the bot also suggested making DrmCursorData carry width and
height as u32 to match the wire. They are i32 because that is what they feed,
protobuf CursorData declares both as int32 and platform/linux.rs assigns them
straight across. One cast has to exist somewhere, and it belongs at the boundary
where the values are already being validated, not at the consumer.

101 tests pass, both configs build.

* drm: bound the body read, and stop the empty key from aliasing displays

From the second review bot on our fork. Two of these are real and one of them is
mine from earlier today.

A raw body read had no deadline. Only the header was bounded, and drm_read_full
loops on readable() until it has the exact length, so a producer that wrote a
header and then stopped (crashed, stopped, wedged) pinned the consumer receive
thread forever. That thread is also the one that observes the stop flag, so every
capturer rebuild would have stranded another thread and its render context. The
whole body is bounded now, and an overrun is a hard error because the header is
already consumed and the frame cannot be resumed.

get_capturer_info collapsed an unknown connector identity to the empty string and
then read and wrote the health map under it, so two unidentifiable displays shared
one entry and one could demote the other. That is exactly the aliasing frame()
refuses to take part in; I fixed one side of it this morning and left the other.
The key is an Option now and both blocks skip when it is None: a display with no
identity simply carries no health.

Also from the same pass, smaller:

- build.py validates the shape of DRMTAP_SHA and DRMTAP_REPO before they reach a
  shell command. Both are env-overridable and get interpolated, and beyond the
  injection argument, an abbreviated sha would defeat the point of pinning while
  failing in a much less obvious place.
- the workflow's push path list is now identical to the pull_request one. It was
  missing four paths, so a push to master touching only those would have skipped
  re-verification.
- the checkouts set persist-credentials: false, so the token does not stay in
  .git/config for the rest of the job.
- a concurrency group supersedes a stale PR run, but never cancels a master run,
  whose whole purpose is to record that a commit was verified.

Not taken: reading VCPKG_COMMIT_ID and FLUTTER_VERSION from a shared .env. There
is no .env at the repo root, and the stock ci.yml and flutter-build.yml hardcode
those same two values, so this matches what is already there.

101 tests pass, both configs build.

* drm: test the half of the accept-time authorization that had none

The review called the accept-time authorization decision the single most
important invariant in this PR, and noted it has no test. Half of it did:
drm_peer_authorized_matrix covers the uid rule. The other half, the
/proc/<pid>/exe identity match that stops a DIFFERENT program running as the
right uid from being handed the screen, did not.

We said last round that testing it needs a second process with a different
executable, so it was integration rather than unit work. That was too
pessimistic: the negative case needs ANY foreign executable, not a second build
of rustdesk, and /bin/sleep is one. So the test covers all three outcomes: our
own pid matches, a live process running another binary is rejected, and a peer
whose pid cannot be resolved is rejected rather than admitted.

The test synchronizes on the child having exec'd before it looks. spawn returns
while the child is still a copy of us, and until exec completes /proc/<pid>/exe
points at OUR binary, so reading it too early sees a match and the assertion
passes for the wrong reason. It failed exactly that way under the parallel suite
and passed when run alone. A real peer has necessarily exec'd and connected
before it can be authorized, so the window exists only in the test.

102 tests pass, three consecutive full runs, both configs build.

* drm: make the refresh decision a pure function, and test it

The review named two untested things: the accept-time authorization decision,
covered by the previous commit, and the availability/demotion state machine. The
demotion half got tests with the backoff work; this is the other half, what a
completed background refresh decides.

It is extracted rather than tested in place on purpose. The effects touch
process-global state, DRM_STATE and the failure counter, which parallel tests
cannot share, so a test driving them would be intermittent by construction, which
is the kind of test nobody ends up trusting. The decision itself has no such
problem, so it is now a total function over the probe result and the consecutive
failure count, and the closure applies it.

Two tests: the decision table, including that a run short of the threshold keeps
a working verdict and the threshold gives it up; and the symptom the policy
exists for, a root service that dies while this server lives, where every probe
fails from then on and the verdict has to be given up in bounded time, to Unknown
rather than Unavailable, because what we learned is about the producer and not
about the hardware.

104 tests pass, both configs build.

* drm: count a display whose frames never match its advertised size

The display list carries the CRTC mode and a frame carries the scanout
framebuffer. Those are two different numbers whenever a CRTC scales a
smaller buffer up to its mode, so such a display fails the geometry guard
on the FIRST frame of every session, having delivered nothing.

That path marked the session as having produced frames, which is what the
zero-frame streak uses to decide a display cannot be served over DRM at
all. So the demotion to PipeWire never armed and the display rebuilt until
the rapid-rebuild guard caught it seconds later, under a message about a
mid-session change that never happened.

Count it instead, through the same bookkeeping the stream-died path uses
(now one helper, so the two cannot drift), and say which of the two cases
the error is. The unit test asserted the old behaviour on a capturer that
had never delivered a frame, so it is split into the mid-session case it
meant to cover and the first-frame case it was silently locking in.

* drm: make an unpinned libdrmtap deliberate, and reject --drm off Linux

Three ways to build a different libdrmtap than the pinned one (DRMTAP_REPO,
DRMTAP_SHA, DRMTAP_PREBUILT_DIR) were each silent, and the last skips the
sha verification entirely. The claim this feature rests on is that the
privileged capture library is the reviewed object at the pinned sha, so any
build that is not that one now has to say so: the overrides still work and
still cover local work and cross-builds, but they need
DRMTAP_ALLOW_UNPINNED=1 alongside them and the build prints what it did.

--drm on Windows or macOS was accepted and then dropped by get_features(),
so it produced a stock build that looked like a DRM one. Reject it.

Also test the _drm body-read deadline, which nothing exercised: the header
and the body are separate reads, so the caller budget does not cover the
second one and a regression there would silently reopen the stall.

* drm: treat an empty DRMTAP_PREBUILT_DIR as unset in the pin gate

build_libdrmtap_so() tests it for truthiness, so an empty value means no
prebuilt directory. The gate compared it against None instead, and would
have demanded the opt-in for an override that was never going to happen.

* drm: never latch the uinput refresh slot, and bound the source stride

The uinput refresh worker released UINPUT_REFRESH_BUSY on its two normal
exits only. The body locks several process-wide mutexes and does a Wayland
roundtrip, so an unwind there left the flag set for the process lifetime,
and every later hotplug then skipped the spawn and never reapplied the
uinput ABS range: the stale-range, wrong-output symptom the refresh exists
to prevent. This file already had the answer for the probe flag, one screen
away, and the hazard is called out in wayland.rs. Fixing one site and not
the other is the same miss as the hotplug maps.

The slot is deliberately handed back and re-taken mid-loop, so the guard
tracks ownership rather than releasing unconditionally: a plain RAII drop
would clear a flag a replacement worker owns.

drm_reader bounded only the destination (w*4*h) while the row loop reads up
to (h-1)*stride + w*4, so a large stride read past the mapping and could
overflow usize in y*stride. drm_render::convert already bounds stride*h;
the privileged half must not be the weaker of the two.

Also give the drm CI jobs a timeout, so a hung meson or vcpkg step fails in
an hour instead of six.

* drm: refuse to ship a libdrmtap built without the EGL backend

libdrmtap treats egl/glesv2 as OPTIONAL: without their headers and
pkg-config files meson silently builds a CPU-only stub. The stub still
exports every symbol the loader gates on, so nothing downstream notices,
and the split capture depends entirely on the unprivileged side
EGL-detiling the scanout it receives. The result is a build where DRM
capture quietly degrades to PipeWire on every tiled-scanout host, which is
most of them. Our CI asserts this on the .so it builds; a developer or
packager running build.py got no such check.

Assert on the artifact rather than passing -Degl=enabled: that option only
exists in libdrmtap past the pinned 0.4.15, and checking what was actually
produced also catches a stale or substituted object, which a build flag
cannot. Same two markers CI looks for, and for the same reason an ELF-level
check does not work: EGL is reached by lazy dlopen so there is no
DT_NEEDED.

* drm: gate the libdrmtap ABI on the minor, and skip the warm probe on X11

Two items from the review that I had recorded as done and were not.

The ABI check had a floor and no ceiling, so 0.5.0 and 0.9.9 passed. Under
0.x semver the minor is the breaking axis, and libdrmtap freezes only
drmtap_device and drmtap_dmabuf_desc: drmtap_frame_info, drmtap_display,
drmtap_config and drmtap_cursor_info are not frozen. A 0.5.0 adding one
field to drmtap_frame_info still reports major 0, so we would have loaded it
and read every field at the wrong offset, in the root service. It now
requires the verified minor; a 0.5.x needs a deliberate bump after comparing
the layouts.

The unit test asserted the opposite of this, in as many words ("0.5.0 must
pass"), so it was holding the hazard in place. Replaced.

warm_availability ran on X11 too, where every consumer of the verdict sits
behind an !is_x11() check, so the root service opened DRM readers for a path
the session can never use.

* drm: close the full-review findings (a third latched flag, and two escapees)

The one that matters: the display-cache refresh worker was the THIRD copy of
the wedged-flag hazard. catch_unwind covered only the enumeration, and
thread::spawn panics on EAGAIN after RUNNING was already swapped true, so
either path parked the flag for the process lifetime and every later refresh
- including every udev hotplug - returned early forever. Same ownership
guard as UINPUT_REFRESH_BUSY (the flag is handed back and re-taken mid-loop,
so an unconditional RAII release would clear a replacement worker's flag),
plus a fallible spawn whose failure drops the closure and releases the slot.
DRM_PROBE_IN_FLIGHT, UINPUT_REFRESH_BUSY, now this: the lesson stays
'grep for every site with the shape', and twice was not enough.

Two findings had been flagged in an earlier round and escaped the ledger:
- an unrecognized convert-output fourcc fell through to 'present as BGRA'
  with a debug log, where every sibling validation in that function is a
  hard error that lets the caller fall back to PipeWire. A 64bpp output
  passes the stride check and encodes garbage. Hard error now.
- the trust-boundary validation constants (fourccs, MAX_DIM,
  MAX_FRAME_BYTES) were declared independently on both sides of the split.
  Hoisted into drm_reader, imported by the converter, so the two halves
  cannot drift apart about what data they will touch.

The rest:
- the CI symbol extraction dropped any loader symbol containing a digit and
  degraded to a pass-with-zero-iterations no-op if the b"..." literals were
  ever refactored; digits allowed, count asserted, notice de-hardcoded.
- 'drm' in features was a substring test on the comma-joined string, so a
  future drm-lease feature would have shipped the consent-bypass deb
  without --drm. Exact membership now.
- the security doc claimed the deb is built on an ubuntu18.04 container;
  the only deb job runs on ubuntu-24.04. The 18.04 sentence now says what
  is true: 2.4.95 is an API floor, the binary floor is the build host's.
- DRM_DISPLAY_CACHE poison handling was recover-in-the-writer,
  panic-in-the-readers; both readers now recover like the writer.
- the producer prewarm ran on X11 where no consumer can connect, the same
  inconsistency just fixed for warm_availability. The listener still starts
  (the service outlives sessions; a later Wayland login must find the
  socket), only the prewarm is skipped.

* drm: measure the verification deb glibc floor and put it in the artifact name

The workflow already said in a comment that this deb is a verification build
with a higher glibc floor than the release debs, because it builds on the
runner rather than in the ubuntu18.04 container the stock job uses. A comment
in this file is not visible to whoever downloads the artifact from the Actions
UI, and the name was a bare rustdesk-unattended-wayland-x86_64.deb, so it read
like something installable anywhere.

The floor is now read off the built object with objdump and goes into the
artifact name, so the constraint travels with the file. Measured rather than
stated: a hardcoded number would drift the next time the runner image moves.
Verified the pipeline against a real deb here (2.39).

Restoring the container build is the other option and is cheap to do -- the
recipe including the two 18.04 traps is still in this repo's history -- but it
belongs with a deb that is actually distributed, not with a job whose contents
are already asserted in-place.

* drm: the same latched-flag bug a fourth time, in my own fix for the third

I built UinputRefreshGuard INSIDE the spawned closure, so it only covered
paths where the closure ran. thread::spawn panics on EAGAIN after the swap,
so no guard existed and the flag stayed set for the process lifetime, which
is the exact failure the guard was introduced to prevent. I then wrote
RefreshSlot correctly - constructed before the spawn, moved in - two hours
later and did not go back to fix its sibling. Both are right now, and the
spawn is fallible in both.

Also from the review:

- DRMTAP_PREBUILT_DIR returned before the EGL-stub assertion, so the check
  only guarded the source build. That is backwards: prebuilt-dir is the
  widest override (no fetch, no sha check, an object this script never sees),
  the likeliest to hand over a stub, and the path our aarch64 cross-build
  actually uses. Verified the assertion accepts a real .so and rejects one
  built with -Degl=disabled.
- convert() bounded only the frame libdrmtap returns, not the descriptor going
  in. offsets/pitches address plane ranges inside the dma-buf, so those are
  what a malformed pair would reach past. Bounded per populated plane, the
  same way the export side is. Defense in depth (the producer is
  root-authenticated and libdrmtap validates against the fd since 0.4.12),
  but the two halves should agree before the C sees the data, not after.
- the flutter patch step used '[[ test ]] && git apply' as its last command,
  so the step would FAIL rather than skip the first time FLUTTER_VERSION
  moves off 3.24.5. Explicit if/else, and the values now come from the
  environment instead of ${{ }} interpolation, which also clears zizmor's
  template-injection warning. Checked both branches.

Declined: the cursor id/cache-key convergence finding. Both accessors use one
selection over one map, so they can only disagree across a publish race, and
state.hcursor is already set to the id ACTUALLY served (drm_served_id), which
is the sync the finding asks for - added in an earlier round.

* drm: stop routing gates from paying for the availability probe

A Major finding I skipped twice, and the file already argued against itself:
wayland.rs's own NOTE says re-probing _drm from the async enumeration path
blocks the executor long enough to trip 'deadline has elapsed' and spiral
into a restart loop -- and then six routing gates called is_available(),
which runs query_displays() inline whenever the state is Unknown (cold start,
or a NEGATIVE_TTL expiry mid-session). ensure_inited, is_inited,
get_displays_and_primary and clear() are exactly the paths the NOTE names.

is_available_cached() is a single mutex read: KNOWN-available or not. The six
gates use it, which is safe because they are routing decisions, not
capability ones -- a cold cache answers 'not DRM' and the caller takes the
PipeWire path it would have taken anyway.

Switching all seven, which is what the finding literally suggested, would
have introduced a worse bug: warm_availability calls query_displays()
directly, so is_available() would have had ZERO callers and nothing would
ever probe lazily again. A --server that started before the root service
would then never see DRM for the rest of its life. get_capturer_for_display
keeps the probing form -- it is sync, on the plain video thread, it is the
capture-build path where a definitive answer is the point, and it is what
makes a cold cache recoverable.

* drm: stop leaking the authorized _drm fd into forked children

libc::dup() does not copy the close-on-exec flag, so the dup'd _drm socket fd
was inherited by every child this process forks. This process is the ROOT
service and it does fork synchronously elsewhere (the loginctl active-uid
lookup), and that fd is an ALREADY-AUTHORIZED channel to the one thing on the
box that hands out scanout dma-bufs. F_DUPFD_CLOEXEC instead. Measured the
difference rather than assuming it: dup() leaves FD_CLOEXEC clear,
F_DUPFD_CLOEXEC sets it.

Also the last two artifact sources without the stub check:

- --package + --drm stages the .so straight out of a bundle somebody else
  produced, with no _assert_so_has_egl. Third source, same exposure as
  DRMTAP_PREBUILT_DIR, now asserted like the other two. All three artifact
  paths are covered.
- the workflow triggers omitted src/server.rs, src/server/input_service.rs and
  src/platform/linux.rs, which all carry DRM wiring (warm_availability, the
  cursor path in run_cursor, the producer start and get_cursor/get_cursor_data),
  so a PR touching only those skipped the entire drm verification. Added to
  BOTH mirrored lists and asserted equal (15 == 15).

* drm: decide x11 inside the prewarm, with a bounded re-check

the one-shot is_x11() gate at the call site misfired during boot:
get_display_server() falls back to "x11" while loginctl cannot name the
seat0 session yet, so on a wayland host with the service enabled at boot
the prewarm was skipped for the life of the service and only ever ran
after a manual restart, which is how every deploy happened to exercise
it.

move the gate inside drm_prewarm and re-ask every 2s for up to 30s. a
genuine x11 or headless host exhausts the budget having opened no
DrmReader and no drm fd; a wayland boot proceeds as soon as the session
reads as wayland. measured on a boot: the skip used to fire 0.8s in
while loginctl reported the wayland greeter in that same second, and
graphical-session.target only arrived at +5s.

* drm: wake idle-disabled displays and settle the topology before the client is promised a list

a compositor that idles long enough does not merely blank a panel: it
disables the connector, leaving no scanout for any capture backend to
read - not drm, not pipewire, not x11. on an unattended box that meant
connecting to whatever was still scanning out (on an apple t2, the
60x2170 touch bar strip) with the real panel sitting disabled next to
it, or a stale cached list advertising a display with nothing behind it
("waiting for image").

the fix has three parts, and where the wake runs is the load-bearing
one:

- the root service answers every _drm handshake with a fresh, settled
  enumeration (drm_enumerate_settled): enumerate, and if a CONNECTED
  display has no crtc, inject one synthetic 1px pointer round trip over
  uinput (rate limited to one per 20s, one winner via compare_exchange)
  and hold the answer until nothing wakeable is left undriven or a 3s
  deadline passes. rate-limited losers wait for the outcome too while a
  wake is recent - answering with the pre-wake list is exactly the
  mid-transition state that produced duplicate, misindexed monitors.
  connectors a wake could not bring back are latched by connector
  identity (device:connector) and the latch is self-refuting: an entry
  later seen scanning out is dropped, so one slow modeset cannot
  disable the wake for the life of the service, and a dummy plug cannot
  suppress the wake for a different panel that idles later.

- the login path refreshes the cached display list over a live
  handshake (refresh_displays_for_login) before peer info is built, so
  the list the client is promised is the post-wake truth and never
  changes under it seconds later. the publish is generation-checked
  against concurrent writers; every failure mode keeps the previous
  cache, so a login can never get harder than before, only truer.

- the capture handshake resolves the display index the client chose by
  connector identity against the handshake list (the service enumerates
  fresh per connection, so an index alone is only meaningful against
  the list it came from), fails the build cleanly when that monitor is
  gone, and no longer republishes its handshake list into the
  availability cache - that unordered write could clobber a newer
  settled list with pre-wake data and re-advertise a reordered list
  under a live session.

the display-list read timeout grows to cover the settle budget
(DISPLAY_LIST_TIMEOUT_MS), or a wake that needs the full recheck would
turn into a spurious handshake timeout on exactly the host it exists
for. removing the display cache from the handshake path also retires
DRM_CACHE_WARMED; the cache still feeds the topology push and the udev
listener.

measured on the t2 (amdgpu panel idle-disabled, appletbdrm touch bar
still scanning out): connect -> wake fires with undriven=1 -> panel
returns in ~330ms -> the same probe answers 2 displays -> the client
starts on the panel. with the panel awake: zero wakes. the root service
still never maps libEGL/libGLESv2.

* drm: close the round-7 review findings

- the renumbering probe in the DrmDisplaysChanged handler now reads the
  pushed list at wire_idx, the slot our monitor held in the service's
  index space, instead of at the index the client chose. the pushed
  list shares the handshake list's construction, so probing the client
  index compared two different index spaces whenever a wake or hotplug
  had renumbered entries - tearing down a healthy stream or missing a
  real renumbering.
- both message-body reads (cpu frame, cursor pixels) now run under a
  deadline. only the header read re-checked `stop`, so a producer dying
  between a header and its body pinned the receive thread forever and
  every rebuild leaked a thread plus its render context.
- the drm cursor cache gets a size ceiling (drm ids are derived from
  the shape's content, so an animated pointer minted a new key per
  shape and the map grew for the life of the service; x11 ids come
  from a small serial set, so the ceiling is gated and the stock build
  is untouched).
- has_non_drm_backed_display reads a two-scalar accessor instead of
  cloning and geometry-augmenting the whole display list on every
  cursor tick.
- the libdrmtap pin validation moved out of import time into
  build_libdrmtap_so(), so leftover DRMTAP_* environment variables or a
  malformed sha cannot fail a stock build that never touches libdrmtap.
- reworded a workflow comment whose literal expression marker broke
  actionlint.

* drm: close the round-8 review findings

- the .so contract check in the drm workflow runs under strict mode:
  without set -e the trailing ::notice echo returned 0 and masked the
  `test "$missing" -eq 0` assertion, so the step passed even with a
  missing loader symbol or a CPU-only stub. the two extraction
  pipelines get an explicit rescue so a zero-match grep still reaches
  the ::error guard that explains WHY instead of dying silently.
- the pipewire-fallback geometry guard no longer compares the physical
  drm size against the portal rect on a single-display host: the rect
  is the compositor's LOGICAL size, so on a scaled output the two
  legitimately disagree (2880x1800 vs 1440x900) and the guard rejected
  the one valid fallback, restart-looping the display instead of
  degrading. on a single-display host the whole-desktop stream is that
  display by construction, so only the position has to agree; the size
  check stays on multi-monitor hosts, where it is what tells one
  connector apart from the full-desktop rect.

* drm: close the round-9 review findings

- strict mode on the remaining two assert steps of the drm workflow
  (the deb-contents assert and the glibc-floor measurement): same
  masking pattern as the .so contract step fixed last round - without
  set -e only the last command's status counts and the mid-script
  checks were decorative. the floor extraction gets an explicit rescue
  so a no-match grep still reaches the `test -n` reporter.
- the security doc states the whole accepted version window (exactly
  the pinned minor with a patch floor; a NEWER minor is refused too,
  because the mirrored struct layouts are only verified against the
  pinned one), and the auditing section carries the command matching
  its leftover-object comment.
- the uinput-missing warning literal lost the embedded space runs a
  reflow had left in it (it is the sole, once-per-process diagnostic
  for that failure and it read as a run-on line with gaps).
- the geometry-mismatch path in frame() hands the taken buffer back to
  the recycler before erroring; dropping it made every rebuild cycle
  re-allocate a scanout-sized buffer.

* drm: document the display wake in the threat model

the wake is deliberate input injection by privileged code, which is
exactly the kind of thing this document exists to state precisely
rather than leave to be discovered in the diff: why it must run in the
root service (uinput is root-only and the compositor holds drm master),
what it can reach (only an already-authorized _drm connection triggers
it), how narrow the trigger is (a connected-but-undriven connector,
with a self-refuting per-connector memory for the hopeless ones), the
rate bound (one wake per 20s process-wide, single winner), the device
lifetime (created and destroyed around the emit), and that a host
without /dev/uinput loses nothing it had (such a session was already
view-only).

* drm: close the round-10 review findings

- the /dev/dri gate returns the CANONICAL path instead of a bool, and
  both callers open that value. answering yes/no meant the caller
  handed the original string to libdrmtap, which re-resolved every
  symlink component after the check - a check-then-use window, in the
  root service. this is the whole point of the gate, so it should
  never have been able to hand back an unresolved path.
- `--package <folder> --drm` builds the capture library instead of
  demanding it inside the bundle. no build path puts libdrmtap in a
  bundle folder (the flutter deb builds it straight into the staged
  deb), so that check made the flag combination impossible to satisfy.
  the safety property it stood in for is now asserted directly and
  better: the staged BINARY must carry the drm dlopen path, so a stock
  binary can never be packaged under the consent-bypass name. a bundle
  that does carry a .so keeps its existing EGL assertion, and the
  variant naming keys on the explicit request rather than on what
  happened to be staged.
- the deb assert step globs into an array and asserts the count: under
  set -e `ls` aborted before its own `test -n` could report, and
  several matches produced a multi-line value whose mv failed with an
  unrelated error.

* drm: finish the logical-geometry comparison, and chain a re-raise

the pipewire-fallback guard now normalizes BOTH sides to logical before
comparing. last round fixed only the single-display case, which left
the same defect on the shape that actually has it: on a multi-monitor
scaled host the advertised geometry carries the PHYSICAL drm mode plus
the compositor scale, while the portal rect is already logical, so a
scaled output disagreed with itself (2880x1800 against 1440x900) and a
per-connector stream that really was that display was rejected,
leaving it advertised offline instead of degrading. the size check
itself stays: on a multi-monitor host it is what tells one connector
apart from the whole-desktop rect. the failure message reports the
logical numbers, the ones actually compared.

also chains the libdrmtap read failure with `from err` so the original
OSError survives (ruff B904).

* drm: fix two review-suggested changes that were wrong, and stop overclaiming in the docs

an adversarial sweep over the whole batch, aimed at the failure that
kept recurring here (a hazard identified and only some instances
fixed), found that two changes made on review advice were themselves
defects. both are reverted with the trace written down so they do not
get "fixed" again:

- the hotplug renumbering probe reads the pushed list at the CLIENT
  index again, not the service one. `bound_to` is an IDENTITY,
  (device, crtc_id), so comparing it against a slot is not a
  cross-index-space comparison; and `swap_available_displays` installs
  that same list as DRM_STATE two lines later, which IS the client
  space - display_service re-advertises it, input is mapped through
  it, the next rebuild reads `expected` out of it. Probing the service
  index answered a question nothing downstream consumes and went quiet
  in exactly the case the guard exists for: a stream whose wire_idx
  differs from its client index kept running while that index came to
  mean another monitor, so the client rendered monitor A believing it
  was monitor B and routed every click accordingly.
- the pipewire-fallback guard compares raw sizes again. BOTH sides are
  physical: `Display::width()` on the wayland variant returns
  `physical_width()`, and `try_fix_logical_size` only repairs the
  capturable's separate logical_size field. Scaling the drm side
  therefore compared logical against physical and rejected the valid
  stream on precisely the scaled outputs it was meant to rescue. The
  single-display carve-out now needs BOTH sides to be single, since a
  monitor on a card the service cannot open is missing from the drm
  list while the compositor still drives it.

also from the sweep:

- a capture build whose index is out of range of the advertised list
  now fails instead of falling back to the raw index, which the wake
  can have grown the service list back past - that bound a second
  video service to a monitor already being served and recorded its
  health under the wrong identity.
- the security doc no longer claims the privileged process never loads
  GL. That is true of the DEFAULT path and measured there, but the CPU
  fallback converts in-process, and a tiled scanout can only be
  decoded through the GPU, so libdrmtap dlopens libEGL in the calling
  process when the frame needs it. The doc now says which property
  belongs to the path and which to the process, and bounds the cases
  instead of overclaiming.
- the wake latch is described honestly: it self-clears when the
  display is next driven by anything, but nothing retries it, so a
  transient failure can leave it latched on an unattended host.
- the wake's uinput device DECLARES two axes and BTN_LEFT (libinput
  ignores a device that does not look like a mouse) while EMITTING
  only the net-zero axis round trip. the doc said one axis and no
  keys, describing the emit as if it were the declaration.
- the drm CI never ran for a change to the root Cargo.toml, where the
  top-level `drm` feature is defined, or to Cargo.lock, which every
  `--locked` build here resolves against. both triggers list them now.
- the deb assertion checks the packaged BINARY carries the libdrmtap
  dlopen path, not just that the library was staged beside it.

* drm: close the round-13 review findings

- the ABI refusal message has a branch for an unverified MINOR. It had
  only two, so a library NEWER than the pinned minor was told it
  "predates the split-capture API" - the opposite of its problem, and
  the kind of message that sends someone looking in the wrong place.
  the warn line names the accepted minor too.
- the libdrm floor no longer claims 18.04 ships 2.4.101: base bionic
  shipped 2.4.91, which is BELOW the 2.4.95 the GetFB2 API needs, and
  only the updates/HWE stack clears it. read as "18.04 with updates,
  or newer".
- the drm-build marker scan reads the staged binaries chunked inside a
  `with`, overlapping by len(marker)-1 so a marker cannot fall across
  a chunk boundary, instead of pulling a 45 MB librustdesk.so into
  memory and leaning on refcounting to close the file. verified
  against a real drm build (found) and an unrelated binary (not
  found).

* drm: close the round-14 review findings

- the .so contract and deb assertions no longer pipe into grep. under
  `set -o pipefail`, `producer | grep -q` reports a FALSE FAILURE once
  the producer outruns the 64 KB pipe buffer: grep -q exits at the
  first match, the producer dies on SIGPIPE, and pipefail makes that
  the pipeline's status - so a library that HAS the symbol is reported
  as missing it and the step fails on a good build. measured on a real
  EGL-enabled .so (101 KB of strings, both markers present): the piped
  form reported both missing. this was introduced by the strictness
  fix two rounds ago and only passes today because a release-sized .so
  fits in the buffer. NOTE the obvious repair does not work either -
  materializing the output and piping the variable keeps the pipe and
  fails identically (measured), so these now match with bash's own
  pattern operator and no subprocess at all. verified with positive
  and negative controls.
- warm_availability decides X11 for itself, inside its retry loop,
  with the UNMEMOISED `scrap::is_x11()`. this is the same one-shot-at
  -startup bug the pre-warm had, in its sibling call site, left behind
  when that one was fixed: the check ran during startup, where
  loginctl cannot yet name the seat0 session and the answer defaults
  to "x11", so a Wayland host that came up slowly skipped the warm for
  the life of the process and got back the cold-probe "No displays"
  symptom the warm exists to remove. the memoised form would have
  moved the bug rather than fixed it, since it latches its first
  answer.
- the grab_desc SAFETY comment says what the frame protocol actually
  is instead of promising a release on every return path: traced in
  the C, a failing grab_desc leaves nothing to release (-EINVAL
  returns before allocating, a failed inner grab has already cleaned
  up, and -ENOTSUP releases the frame itself), so releasing on those
  paths would be a double free.

* drm: bound the work an unauthenticated peer can make the root service do

the `_drm` socket is world-connectable by design (the unprivileged
--server has to reach it), and every accepted peer got a spawn_blocking
authorization - which forks `loginctl` whenever the active-uid cache
misses - BEFORE any admission bound applied. MAX_DRM_CONNS does not
help there: it only counts peers that already passed. So a local uid
that will be rejected could still open connections in a loop and keep
the shared blocking pool busy, and that pool is shared by every live
capture stream, which is exactly the stall the comment above the
authorization warns about.

add a separate, small in-flight bound around the authorization step,
deliberately NOT the same counter as MAX_DRM_CONNS: sharing one would
let a rejected flood eat the capacity the real consumer needs. the
guard is taken before the spawn and released as soon as the verdict is
in, so the slot covers the authorization only. the rejection logs at
debug rather than warn for the same reason the existing rejection is
silent - anything reachable by any local uid must not be an unbounded
log-write primitive. unit-tested like its sibling, including that the
pre-auth bound stays the tighter of the two.

* drm: reject an out-of-range num_planes on the import side instead of clamping it

the incoming descriptor's plane count was clamped to 1..=4 for the
validation loop but passed to libdrmtap RAW, so a wire descriptor
claiming 7 planes was checked as if it had 4 and then handed over
claiming 7. the pinned libdrmtap refuses >4 itself, so this was not an
overflow today - but the stated purpose of that block is that the two
halves of the split agree about what they will touch BEFORE the C sees
it, and that only holds if the count travelling with the descriptor is
the count this side bounded. it also stops this half depending on an
internal check in a library pinned from another repo.

reject and normalize instead, which is what the EXPORT half already
does in grab_desc; the two sides now have the same shape.

* drm: close the round-17 review findings

- the scanout dma-buf fd is duplicated with F_DUPFD_CLOEXEC. `dup(2)`
  never copies close-on-exec, so this fd was inherited by every child
  the ROOT service forks (it forks synchronously for the loginctl
  active-uid lookup) - and what this fd names is the live screen
  contents. this is the SAME defect already closed on the `_drm`
  socket fd in ipc/drm.rs; fixing that one and not grepping for the
  siblings is how this survived. there is exactly one dup in the drm
  path now and it is this one, verified by grep. measured that
  F_DUPFD_CLOEXEC sets FD_CLOEXEC and preserves the O_RDONLY access
  mode the read-only export depends on; SCM_RIGHTS delivery is
  unaffected since the receiver gets its own descriptor.
- Desktop::refresh resolves HOME on the login-Wayland path too, since
  the drm build now starts a --server as the greeter uid there and a
  child with no HOME has nowhere to put its config. the compositor
  variables stay blank deliberately: the drm path talks to the root
  service and a render node, never to the compositor or the portal,
  which is why it works at a login screen at all. reasoned, not
  measured: a current GDM runs its greeter as `gdm-greeter`, which
  `is_gdm_user` does not match, so that path is not reachable on our
  hardware - measured there, the greeter server gets a fully populated
  environment through the branch below.
- the glibc-floor step globs into an array and asserts the count, like
  its sibling assert step. that sibling was fixed two rounds ago and
  this one was left behind.

* drm: put the display wake behind its own compile gate and a runtime option

everything else in this backend READS: it captures a scanout. the wake
WRITES, injecting one synthetic pointer event from the root service
into the user's session. that is a different kind of operation and it
should be switchable on its own, at both levels.

- compile: a `drm-wake` feature on top of `drm`. every wake-only item
  is gated and drm_enumerate_settled has two definitions, so
  `--features drm` builds the same capture path with no wake code in
  the binary. verified on a RELEASE artifact with both controls: the
  drm markers are present (Started drm ipc server) and the wake string
  is gone. the unattended deb passes drm-wake, so answering an
  objection is one word in build.py rather than a revert.
- runtime: `enable-drm-display-wake`, server-side, the same shape
  rustdesk already uses for the closest thing it does to this
  (keep-awake-during-incoming-sessions, which PREVENTS sleep where
  this RECOVERS from it, and is acquired only once a connection
  exists, which is too late for a host that cannot be reached).
  the `enable-` prefix is load-bearing: option2bool reads an absent
  value as ON, and a host whose screen went dark is the case the
  unattended package exists for. set it to "N" and the service stays
  read-only with respect to input.

the key is declared in this file rather than in hbb_common's `keys`
module, where rustdesk's own option constants live: hbb_common is a
submodule of a repo we do not control, so a constant there could only
land after an upstream change plus a submodule bump. the option system
reads by string, so registration is not required; the cost is that the
key is set in the config file rather than the settings UI, which is
how an unattended host is configured anyway.

* drm: enumerate /dev/dri by path instead of trusting one auto-detected card

when `list_devices` gives us nothing to work with, the fallback was a
single auto-detected reader. that is the wrong unit of enumeration on a
multi-card host, and the reason is worth keeping: libdrmtap's
auto-detect picks a card that is SCANNING OUT, so when the interesting
display is asleep it picks a DIFFERENT card and we enumerate only that
one. the asleep display is then invisible - not as a display, and not
as an undriven connector either, which is what the wake keys on.

measured on the t2 with the panel idle-disabled, through a direct
libdrmtap call: auto-detect succeeds and binds card0, the touch bar,
because the touch bar is what is still scanning out; the 2880x1800
panel on card2 is invisible to that reader, while opening card2 by
explicit path in the same instant reports `eDP-1 crtc=0 active=0`
exactly as needed.

so walk /dev/dri/card* and ask each, with auto-detect demoted to a last
resort for the case where no card opens by path. this path is reached
only when list_devices is unavailable (a pre-0.4.15 .so) or opened
nothing, so it costs nothing on the normal path - it is defensive, not
a fix for anything observed with the pinned library.

the enumeration result is logged UNCONDITIONALLY, including the empty
case, because a silent "found nothing" gives no way to tell an empty
host from a failed enumeration.

* docs: state the per-frame reauthz and the wake's one-shot bound

Two things the security doc left implicit, both measured on 2026-07-31.

The `_drm` authorization is described as per-connection, which undersells it.
DRM/KMS capture is not session-scoped - it grabs the physical scanout of a CRTC
no matter which session owns the display - so the check is re-run on every
frame, and when a user logs in at a greeter the greeter's stream is closed
rather than continued. That is the property that stops an outgoing greeter
process from capturing the screen of the user who just logged in, and it is
worth stating where a reader is looking for exactly that confinement.

And the wake section never said what happens after the wake. It resets the
compositor's idle timer; it does not hold the display on. Left alone, the
connector idles off again one full idle period later: 30.3 s at a GDM greeter,
70.3 s in a user session with idle-delay=60. Saying so makes the existing
"useless as a way to keep a screen lit" clause concrete, and points at the
component whose job that actually is.

* drm: ship the wake in the CI deb, and assert the artifact on both package paths

Three findings from the round on the wake-gate commits, all the same shape: the
gate made "what was asked for" and "what was produced" diverge, and two places
still trusted the first.

CI built the unattended-wayland deb with `--features ...,drm` and then packaged
it with `--skip-cargo`. build.py appends `drm-wake` for `--drm`, but skipping
cargo means whatever that explicit line compiled is what ships, so the deb had
no wake code in it at all while being named and documented as the variant that
has it. The feature list has to be complete on the line that actually builds.

The marker assertion that catches exactly this class only guarded one of the two
packaging paths. `build_deb_from_folder` asserts that the staged binary carries
the libdrmtap dlopen path before it takes the unattended-wayland name; the
flutter path did not, and `--skip-cargo` reaches that one. A stock binary could
therefore be packaged under a name that conflicts with and replaces the stock
package, and then never capture. Hoisted the check to module level and called it
from both, before the bundle is renamed.

And the security doc described the synthetic input injection as an unconditional
property of a drm build. It is behind its own compile feature and a runtime
option, which is exactly what an operator auditing the deb needs to know.

* drm: stop a delivered frame from erasing the two verdicts it says nothing about

A deep review pass over the whole branch, run because a maintainer once found
two bugs here that nineteen rounds of an automated reviewer had missed. Three
findings, two of them the same root cause, all confirmed by re-reading the code.

The first frame of a session dropped the display's whole health entry. That is
right for the zero-frame streak, which is exactly the verdict a delivered frame
refutes, and wrong for the other two:

- `last_build`/`rapid_builds` exist for a display that delivers a first frame
  and then fails downstream every cycle. Wiping the cadence on that frame meant
  the flap guard could never reach RAPID_REBUILD_MAX in the one case its own doc
  comment describes. It was a guard that could not fire.
- `prefer_cpu` records which GPU exports a monitor, a property of the host, and
  is documented as following the monitor for the process run. Erasing it on the
  first frame it made possible meant every rebuild re-paid a dead dma-buf
  session: fail, learn, take the CPU path, forget, fail again. It never demotes,
  because the CPU session clears the streak each time, so it repeats for the
  process lifetime. Worse, the bit is set on the recv thread and was deleted on
  the encoder thread, so a convert failure racing a queued frame could destroy
  it inside the very session that learned it.

So reset only the streak. Only a topology change, where the GPU mapping really
can have changed, may still clear the convert verdict.

Second, `get_primary_index` was a second, weaker copy of the connector-to-output
matcher: name-only, with neither the unique-resolution step nor the layout-order
fallback the augmentation grew. On a compositor whose names do not normalize to
the DRM names it answered 0 while the geometry augmentation had matched that
display to a different output, so the advertised primary and the advertised
geometry disagreed. It now asks the same assignment, which makes them agree by
construction.

Third, packaging asserted half of what the deb claims. `assert_staged_binary_is_drm`
looked for the libdrmtap dlopen path, which `--features drm` alone also carries,
so a bundle built without `drm-wake` could still be named and documented as the
variant that wakes an idle-disabled display; it now requires the wake marker too.
And nothing anywhere checked that the libdrmtap being shipped is one the runtime
would accept: `abi_accepted` is the only validation of the pinned version and it
runs at dlopen time on the user's machine, so the pin and the gate could drift
and every existing assertion would still pass -- EGL markers say nothing about
the version, the CI symbol contract never calls drmtap_version(), and the deb
regex matches any version. Staging now applies the gate parsed out of the Rust,
so a green build cannot produce a deb whose capture can never start.

* drm: fix the ABI cross-check's path, and stop panicking on a failed spawn

The ABI cross-check added in the previous commit could never run: both callers
of stage_libdrmtap_into_deb chdir into flutter/ first, and the check opened
drmtap_dl.rs by a path relative to the cwd, so every --drm packaging run died
with FileNotFoundError. CI caught it. It is anchored on __file__ now, and read
through a context manager.

Worth naming why the test missed it: the check was exercised from the repository
root, which is the one directory where the bug is invisible. A control that does
not reproduce the call site's conditions is not a control.

Three more, all the same class the previous commit was already fixing - a
hazard closed at one site and left at its siblings:

- `std::thread::spawn` panics when the thread cannot be created, and the panic
  unwinds into whoever called it. The two hardened workers used Builder; the
  five remaining DRM threads did not. The startup ones now log and degrade (a
  lost pre-warm costs one cold probe, a lost udev listener costs the mid-session
  push, a lost warm costs the first session), and the two per-session ones live
  in functions that already return ResultType, so they fail that one connection
  cleanly instead of unwinding through the handler.
- The wire descriptor's `num_planes` was clamped to 1..=4 here while
  `drm_render::convert` rejects an out-of-range count on purpose, so that the
  count the C reads is the count this side validated. Clamping made that reject
  unreachable: a descriptor claiming 7 planes arrived as 4 and passed. The two
  guards were added by different review rounds and had been quietly cancelling
  each other. The raw value is passed through now, leaving one validation site,
  next to the code that dereferences it.
- A SAFETY comment claimed the cursor is released only on success. It is
  released on every path after a successful get_cursor; only a failed get_cursor
  returns without releasing, because then there is nothing to release. The
  release protocol is the reason that block is unsafe, so the comment describing
  it has to be right.

* drm: convert the last panicking spawn, and resolve geometry outside the lock

The spawn conversion in the previous commit missed one. `query_displays` still
used `std::thread::spawn`, which panics when a thread cannot be created, and it
is reached from both `get_capturer_info` and `warm_availability` - so the panic
would land on the capture-build path rather than being reported as the failed
probe every caller already handles. There are now none left in the two DRM
files.

Worth writing down how it survived a pass whose whole purpose was to find it:
the previous commit enumerated the siblings with a grep piped through `head`,
there were eleven matches, and `head` printed ten. The one it cut is the one
that was missed. Same shape as a build log read through `tail` and a `find`
given `-xdev`: the tool truncated the survey and the survey looked complete.
When enumerating sites for a class fix, do not pipe the enumeration.

Also, `get_capturer_for_display` resolved the advertised DRM geometry while
holding the `CAP_DISPLAY_INFO` read guard. That lookup runs a compositor output
roundtrip, and `clear()` takes the write guard on every capturer teardown -
which is what is happening when a display is demoted or flapping, i.e. exactly
when this path runs. The value does not depend on anything inside the guard, so
it is resolved before taking it.

And the security doc listed the unattended package's `Conflicts`/`Replaces` but
not its `Provides: rustdesk`, which is the field that lets a third-party package
depending on `rustdesk` be satisfied by the consent-free variant. An operator
auditing that metadata needs all three.

* drm: test that a delivered frame keeps the cadence and the convert verdict

The guard this locks in could never fire before: a delivered frame dropped the
whole DisplayHealth entry, which took last_build/rapid_builds with it, and those
exist precisely for a display that delivers a first frame and then fails
downstream every cycle. prefer_cpu went the same way, erased by the first frame
it had made possible.

The test drives the real frame() path through the existing harness rather than
simulating the bookkeeping, and it was checked against the old behaviour: with
the entry removed again it fails on "the entry must SURVIVE a delivered frame".
A test that has not been seen failing is not evidence.

* drm: bound the two waits a peer could hold open in the root service

A review pass over the privileged side, reading src/ipc/drm.rs as a local
unprivileged attacker. Two findings, both confirmed by tracing every link.

The wire had a deadline in one direction only. Every read has been bounded since
the beginning, and next_raw_into even carries the argument for it: a peer that
writes a header and then stops pins the other end forever on a readiness wait.
The write side had no deadline at all. That asymmetry costs more here, because
the parked task is in the root service: a peer that simply stops reading - a
kill -STOP on its own --server, a ptrace stop, a frozen cgroup - leaves the send
blocked inside the forward loop, so the loop top is never reached again. The
credit stall, the per-frame reauthorization and the topology-generation check
all live at that loop top, and the connection slot, the worker thread and its
DRM context stay pinned until the peer chooses to resume. drm_write_all is the
single funnel for both directions, so one deadline there covers every send; the
consumer's frame-ack write had the same shape and gets the same bound.

And drain_frame_acks looped until WouldBlock, which is a promise the peer gets
to keep. It is synchronous on the single-threaded _drm runtime, so a peer that
writes a continuous stream instead of one ack byte per frame keeps the receive
queue non-empty, never yields, and pins that thread at 100% CPU - starving every
other stream on it, which on a multi-monitor client means one connection wedging
its own siblings. Capped per call, with an early return once the credit budget
is full; anything left stays queued for the next pass.

Three comments were describing a mechanism that no longer exists. Two still said
a delivered frame drops the whole health entry, which stopped being true when
that was narrowed to zeroing the streak; the third, written in that same change,
pointed at drm_clear_prefer_cpu, a function deleted several commits earlier. The
convert verdict having no clearing site is correct and now says why: it is keyed
by connector identity, so a monitor that moves to another GPU arrives under a new
key and starts clean.

Also, the new regression test held the process-wide health mutex across its
assertions, so the one failure it exists to report would have poisoned that mutex
and buried itself under unrelated PoisonErrors in its sibling tests. It copies
the record out and releases the guard first, as the module's own helper does.

* drm: clear the stale _drm entry by fd, and fix three comments that argue backwards

new_drm_listener cleared the stale socket with std::fs::remove_file, which is
unlink(2). Against a directory-typed squatter that returns EISDIR and leaves the
entry in place, and endpoint.incoming() then fails EADDRINUSE, so DRM capture
falls back to the portal for the rest of the boot over an entry we could have
removed. The _service listener has never had that hole: it removes entries
through a no-follow fd on the parent directory, fstatting the entry first and
choosing AT_REMOVEDIR when it needs to. That helper now takes a path instead of
a postfix, so the _drm listener - which deliberately stays outside hbb_common's
postfix machinery - can use the same one on the directory it just hardened. The
precondition is narrow (an unprivileged process has to win the creation race
before the root service first hardens the dir on a fresh boot), which is why the
failure is a warn and not a bail.

Three comments stated their reason backwards or more strongly than the code
supports. None of them changes behaviour; all three would send the next reader
to verify the wrong thing.

The wake's 20 s rate limit was justified as being short enough to be useless as
a way to keep a screen lit. That is inverted: a shorter gap would make relighting
easier, not harder, and 20 s is below every idle period we have measured (30.3 s
at a greeter, 70.3 s in a session). What actually bounds it is that the wake is
one-shot, which the next sentence of the same doc already says. Fixed at both
sites, the constant and the security doc.

The doc block above drm_enumerate_settled reads as one paragraph but spans a cfg
split, so its shared contract and the wake-less specialisation looked like one
statement about the arm below it. Marked explicitly.

And get_primary_index claimed its answer agrees with the advertised geometry by
construction, which is true only where augment_with_wayland_geometry runs the
same assignment - it declines below two connectors or two outputs, and in that
band the two functions run different code. The answer is still never worse than
the documented fallback there, and now the comment says which.

* drm: test that the fd-based removal clears a directory squatter

The regression this pins is the one the previous commit fixed: a stale entry in
the IPC parent directory is not necessarily a socket, and unlink(2) refuses a
directory. The test asserts remove_file fails on it FIRST, so a passing run
cannot be vacuous, and it checks the second call succeeds too, since this runs
before every bind.

Confirmed red against a neutralised helper before being kept.

* drm: fix what the previous commit's own comments got wrong

A review pass over 08d311d60 - the commit whose stated job was correcting three
comments that argued backwards - found that four of its replacements were wrong
in turn. Two independent passes agreed on each. This is the correction.

The 20 s gap paragraph was never attached to the constant. It is the first
paragraph of a doc block that runs on to OPTION_ENABLE_DRM_DISPLAY_WAKE, so it
documented a config-key string, while DRM_WAKE_MIN_GAP three lines below had no
doc at all. That misplacement predates the previous commit; expanding the
paragraph from one line to five without noticing does not. Moved onto the
constant.

Its content was also wrong for the second time. Saying the limit is not what
stops a screen being held on was right; naming the one-shot property as the
thing that does bound it was not. One-shot cannot bound a repeated relight when
the permitted repeat interval is shorter than the idle period, which is exactly
what the sentence before it establishes: 20 s against a measured 30 s. An
authorized peer that keeps reconnecting can have the panel relit shortly after
each idle-off, and what makes that acceptable is the authorization itself - root
or the active session's own uid, who can hold their screen on with
systemd-inhibit and need nothing from us. Both the constant and the security doc
now say that, and the constant carries a note not to write the old claim a third
time.

The shared contract of drm_enumerate_settled sat on the arm the shipped build
compiles out. build.py --drm adds drm-wake, so a maintainer opening the real
function found it undocumented while a doc comment marked "shared" hung off its
dead twin. A doc comment cannot attach to two cfg arms, so the shared part is
now a plain comment above both and each arm keeps a short doc of its own.

get_primary_index claimed a sole compositor output is matched to the lowest
connector. It is not: pass 1 matches by normalised name and by unique resolution
before any layout-order fallback, so the answer in that band can be any index.
The conclusion survives - a name match is better evidence than a blind 0 - but
the reason given for it was false, and the reason is what the next reader uses.

And the directory case is narrower than it was written. AT_REMOVEDIR is rmdir,
so what the previous commit closes is the EMPTY squatter; a non-empty one still
returns ENOTEMPTY and still blocks the bind. Left that way on purpose - the cure
would be root recursively deleting a tree an unprivileged process planted in a
world-writable directory - and now stated at all three sites plus pinned by the
test, which also stops claiming to cover the call site it does not reach.

* drm: say less in these comments, since saying more keeps being wrong

Third pass over the same comments, and the third set of errors in them. The
pattern is not that any one sentence was careless, it is that every additional
explanatory sentence is another falsifiable claim, and the ones that keep
failing are the ones that reach past what the file can support. So this is
mostly deletion: net fifteen lines fewer.

The "SHARED CONTRACT" header was wrong about its own first paragraph. That
paragraph describes waking, waiting and a rate-limit race, none of which the
wake-less arm does - and the previous commit went further and pointed the
wake-less arm's own doc at it, so that arm now claimed to do the thing the very
next line said it does not. Only the second paragraph, on why an idle-disabled
output is the trigger, is genuinely common to both. That stays above the pair as
a plain comment; the wake behaviour moves onto the wake arm, where it is true.

DRM_WAKE_MIN_GAP no longer argues about why unbounded relighting is acceptable.
It named the wrong actor: the _drm peer is always our own unprivileged --server,
while the party whose reconnects drive the relight is the remote client, which
is neither root nor the local uid and cannot inhibit anything. The constant now
states what it bounds and what it does not, and stops there. The security
document makes the acceptability argument instead, and makes it about the right
party: a peer already authorized to watch that screen gets it lit, which is
visible to a person standing there, not additional access.

Two narrower ones. The helper said a non-empty squatter yields a named error
"instead of" EADDRINUSE; the caller gets both, and the sibling comment in the
listener already said "ahead of", so the same commit disagreed with itself. And
get_primary_index claimed the two functions disagree across the whole band where
augmentation declines, which is false for zero outputs and for a single
connector - it now names the one case that matters.

Not touched, and pre-existing: MAX_DRM_CONNS's doc block has the same wrong-item
defect (it opens on a function and ends on the cap), and drm_enumerate_all_displays
runs two paragraphs together. Both predate this branch's comment work and neither
belongs in a commit about it.

* drm: give the send deadline one budget for the whole write, not one per wait

The earlier commit put the timeout inside the loop, so the budget restarted on
every iteration. A peer that accepts a byte just inside each window, or that
keeps the socket flapping back to WouldBlock, re-arms it forever and the root
task stays parked exactly as it did before - which is the stall the constant's
own doc says it bounds. The diagnosis was right and the fix did not implement
it. Both send paths now take one deadline before the loop and wait with
timeout_at.

Swept the rest of the file for the same shape. The credit wait re-arms a 1 s
poll on purpose and is fine: its total bound is CREDIT_STALL, measured at the
loop top from credit_since, and its comment already says the deadline is
enforced there and not in the poll. That is the pattern the write path was
missing. The read paths are single-shot bounded, not loops.

Not covered by a test. Reproducing it needs a peer that accepts a little data
just inside each window, so the scenario runs longer than the 5 s budget itself
and a no-progress peer - the case a simple test would build - times out
correctly under both the old code and the new.

* drm: stop claiming the wake-less build cannot inject input

It can. Dropping drm-wake removes injection from the CAPTURE path and nothing
else: start_os_service calls start_uinput_service unconditionally, with no
feature gate, so the root service runs RustDesk's keyboard and mouse uinput
backends on every build, drm or not. That is how remote control works on
Wayland and is not ours to change - but a maintainer auditing "is the injection
path present in this build?" was being told no by a comment in the file most
likely to be read for that question. The line now says what is actually true of
the capture path and points at the ungated call, so the next reader is not sent
to verify the wrong claim.

The sentence is inherited: it came in with 2648ad0a2 and survived two review
rounds because both were reading the comments I had just CHANGED, and this one
I only re-wrapped. Re-wrapping is re-asserting.

Also narrowed the wake arm's "the wait applies to every handshake that saw an
undriven display": four early returns skip it - option off, nothing wakeable, no
uinput, no recent wake to settle - and the same block asserts the first of them
four lines later, so the paragraph contradicted itself. And "the trigger" in the
shared block lost its antecedent when the wake paragraph moved onto the wake
arm; it is "the signal" now, which is true for both arms.

* drm: put two doc blocks on the items they describe

Both pre-existing, both found by walking every doc run in the file down to the
item it attaches to rather than by reading prose.

handle_drm_conn's description was stranded: the block opened on the function and
ended on the connection cap, so it attached to MAX_DRM_CONNS while the function
itself had no doc at all. Moved the function's paragraph onto the function; the
cap keeps its own.

And drm_enumerate_all_displays ran its enumeration paragraph and its return-value
paragraph together with no separator, so they read as one. Blank doc line between
them. No text changed in either case - this is placement only.

* drm: pin the send deadline with a test, and close five review findings

The send deadline had no test, and I had written down that it could not have
one: a peer that never reads times out correctly under the broken per-wait form
too, so the obvious test proves nothing. That is true and it is not the whole
answer. A peer that DRIPS separates them, and the first version I wrote still
did not - draining a kilobyte at a time never makes the socket writable again,
because Linux asserts POLLOUT on a stream socket only once a decent fraction of
the send buffer is free, so the sender saw one long readiness wait and both
forms timed out identically. At 64 KiB the socket really does re-arm and the two
diverge. Measured both ways: the test passes in five seconds against the fix and
fails at twenty against the per-wait form, with the message it exists to print.
The chunk size is documented in the test for exactly that reason.

Four more, all verified against the code before touching it:

grab()'s SAFETY block claimed the frame is "released on every path". The ret < 0
arm returns without releasing, because a failed grab_mapped leaves nothing to
release. Its two siblings, grab_desc and cursor, already state the distinction
precisely; this was the loose copy, and the release protocol is the reason the
block is unsafe in the first place.

drmtap_dl.rs still said minor bumps are additive and compatible. abi_accepted
requires an exact minor match and the block below it explains why, so the file
argued both sides and the stale half is an invitation to widen the gate.

grab_desc validated width, height and plane count but not pitch or offset, while
the converter bounds pitch * height + offset per plane. Same bound on the export
side now, so both halves refuse the same descriptors - the principle grab()
already states. No pixel access happens there, so this is not an out-of-bounds
fix; it keeps a bogus pitch off the wire and puts the rejection on the side that
can name the device.

And the deb staging interpolated so_path unquoted, which breaks on a path with a
space (DRMTAP_PREBUILT_DIR is user-supplied).

Also covers the regular-file case through the new removal helper - the stale
socket every restart hits, which the existing file test reaches by another path.

* build: quote the rest of the path interpolations, not just the two that were named

The previous commit quoted so_path and stopped there, which left the six shell
commands that build libdrmtap interpolating src and build_dir bare. Both derive
from repo_root, which is built from __file__, so a checkout under a path with a
space splits the argument and git init, git remote add, git fetch, git checkout,
meson setup and meson compile all fail with an error that says nothing about the
real cause. Same defect, same fix, and quoting one pair while leaving its
siblings is the shape a reviewer finds next.

* fix(drm): close the review items on the capture backend

Guard the producer thread, surface a swallowed spawn error, stop the CI
feature list from drifting from build.py, and four smaller ones.

Should-fix:

- `start_os_service` started the DRM producer with a bare `thread::spawn`,
  the one spawn in this feature that was not built with `thread::Builder`.
  `spawn` panics if the thread cannot be created (EAGAIN under a thread or
  memory limit), and that panic unwinds out of `start_os_service` and takes
  the root service with it -- for a feature whose failure should only cost
  DRM capture. Builder + warn, like the other four.

- `refresh_available_async` dropped the spawn result on the floor. There is
  no wedge (the single-flight guard moved into the closure and is dropped
  with it), but a refresh that can never start was invisible: the cached
  verdict just keeps being served past its TTL. The sibling spawn already
  logged; now both do.

- The drm workflow hardcoded the cargo feature list because it packages with
  `--skip-cargo`, so `get_features()` in build.py and the CI line were two
  definitions of the same thing and only the drm/drm-wake half was asserted
  afterwards. Adds `build.py --print-features`, which prints the list those
  flags select and exits, so CI asks instead of repeating; the same flags now
  drive the compile and the packaging. The step asserts the answer really is
  a drm build before handing it to cargo, matching whole comma-separated
  tokens so a future feature merely containing "drm" cannot satisfy it.

Smaller:

- The ENOTSUP fallback in `drm_capture_worker` switched to the CPU path
  without clearing `stalled`, so stalls charged to the dma-buf path could
  trip MAX_STALLED early and close a connection the fallback was about to
  serve.

- `FrameSlot` kept one recycled buffer and claimed at most one is idle at a
  time, which does not hold: the receive path supersedes an unconsumed frame
  while the encoder returns its borrow, and those two writers do not even
  share a lock, since the receive path takes a buffer and publishes in two
  separate acquisitions. The later write freed a scanout-sized allocation the
  recycler exists to keep. Two slots is the exact bound for three in-flight
  buffers. The existing test passed against this, so the new one counts the
  offers rather than asking whether any came back.

- `get_cursor`/`get_cursor_data` use the memoised `is_x11()` while the
  capture path deliberately uses the unmemoised `scrap::is_x11()`. That is
  the right trade at cursor cadence, since the unmemoised form forks
  `loginctl` per call -- say so, because the surrounding code argues the
  opposite for its own callers.

* docs(drm): cut the changelog prose out of the comments

Removes passages that document this patch's own revision history rather
than the code, including the four quoted in review. Deletions and one
misplaced comment moved to the field it describes; no comment was
reworded, so nothing here can state something new.

- `drm_capturer.rs`: the `drm_clear_prefer_cpu` parenthetical (that
  function does not exist), "same mistake, same shape, as the two flags
  before it" (it names no identifier, and both sites it gestures at carry
  their own hazard comments), and "the comment was right and the code used
  the probing accessor anyway".
- `drmtap_dl.rs`: "this test replaces one that asserted the opposite", and
  "that sentence used to live here" -- the instruction not to widen the
  gate on the strength of "minor bumps are additive" stays, since that is a
  live constraint rather than history.
- `platform/linux.rs`: the "NOT REPRODUCIBLE ON OUR HARDWARE" provenance
  label. What it introduced survives and is the better form of the same
  warning: on the test host `is_gdm_user` does not match `gdm-greeter`, so
  that branch is dead there and the code is for display managers whose
  greeter user does match.
- `ipc/drm.rs`: "and that sentence has already been wrong here twice". The
  warning it trailed stays, because a shorter gap really would make
  relighting easier and the constant should not be described as bounding
  how long a screen stays lit.
- `build.py`: "the answer to an objection is one word, not a revert".

Also moves the comment describing `cur` off `display`, where a field
reorder had left it sitting above that field's own comment.

Most of the remaining density is mechanism, measurement or a hazard, and
is left alone: the pipe/SIGPIPE analysis, the physical-vs-logical rect
comparison, the `wire_idx` vs `display` argument, the wake measurements
(REL_X alone did not wake the panel; the device bind window), the
F_DUPFD_CLOEXEC privilege-leak argument, and the SAFETY blocks.

* docs(drm): condense the capture comments from 35% of lines to 6%

The five DRM files were 2319 comment lines against 4181 of code. The rest
of this repository runs at 3%, so they were roughly twelve times the
surrounding density, and that was the fair reading of the review: the
volume itself is what makes an 8k-line addition hard to review.

They are now 302 lines. What went is rationale: alternatives considered
and rejected, arguments for why a design is acceptable, restatements of
what the next line of code plainly says, and the same fact repeated at
several sites.

What stayed is what a reader cannot recover from the code, kept to one or
two lines each:

- every SAFETY comment on an unsafe block (none was dropped)
- ownership and release contracts with the libdrmtap C API, including
  which grabs own a frame and which must not release it
- ordering requirements: announce a pending refresh before claiming the
  single-flight slot, take the busy flag before the spawn rather than
  inside the closure, never hold DRM_STATE while taking a per-display map
- the flow-control protocol, both ends of it
- wire-format and units conventions, and the cmsghdr alignment the
  control-buffer type exists to provide
- measured facts, reduced to the measurement: which synthetic events wake
  an idle panel and which do not, and the device bind window
- hazards on the world-connectable listener, including why the rejection
  paths log at debug or not at all

No code changed: with comments and blank lines stripped, all five files
are byte-identical to their previous contents. Tests are 111 in the
rustdesk crate and 20 in scrap.

* docs(drm): restore the wire_idx argument on the hotplug guard

The condensation cut this one too far. Within minutes of the shortened
version going up for review, a reviewer read the remaining line and
proposed changing the probe from `display` to `wire_idx` -- which is the
change that was already tried here and was wrong.

So the argument is not rationale prose, it is what stops a plausible and
incorrect edit to a guard in the capture path, and it goes back in at six
lines: `bound_to` is an identity rather than a position, the swap below
installs this list as the client-space DRM_STATE, and probing `wire_idx`
would go quiet in precisely the case the guard exists to catch.

* docs(drm): correct what an empty render_node means on the wire

The condensed doc said "Empty = auto-select", which is false on the host
that field exists for. `drm_capture_worker` computes
`ambiguous_gpu = render_node.is_empty() && render_node_count() > 1` and
folds it into `force_cpu`, so an unnamed exporter on a machine with
several render nodes takes the CPU path rather than auto-selecting. It
auto-selects only where there is a single node.

* docs(drm): fix comment claims that do not match the code

An audit that verified every comment claim against the CODE (rather than
against the pre-condensation text, which is what the earlier pass did)
found twenty that were false or unqualified. Some came from the
condensation dropping a qualifier; several predate it.

The ones that mattered most:

- `drm_render.rs` said libEGL/libGLESv2 are loaded "never in the
  privileged root service". That is true of the split path only: the CPU
  fallback calls `drmtap_grab_mapped`, whose auto-process step reaches
  `drmtap_gpu_egl_convert` in the CALLING process. `DRM_CAPTURE_SECURITY.md`
  already documents this precisely, and `drm_reader.rs` already said "on
  this path"; this one comment had lost the qualifier.
- "A miss is fail-closed" on the per-frame reauthorization: true for a
  non-root peer only, since `drm_peer_authorized` returns true for uid 0
  before it compares against the active session.
- The cursor body check was described as a no-op because the hidden
  sentinel supposedly arrives 0x0 with an empty body. It arrives 1x1 with
  four bytes, so the check is live.
- "EVERY write to DRM_STATE goes through here": the TTL restamp writes
  directly, and the comment on that arm says so.
- `open(crtc=0)` was described as selecting the "primary" CRTC; libdrmtap
  picks the first CRTC with a valid mode, and in that library "primary"
  names a plane.
- `list_devices() == None` was described as leaving the caller on
  single-device auto-detect; the caller scans /dev/dri/card* itself.
- The framing note claimed the whole channel is length-prefixed; the
  reverse-direction frame acks are bare bytes.

Also corrects `buffer_id`, which was documented as the producer's stable
pool key: it is fb_id tagged with a per-connection epoch and no consumer
reads it today.

No behaviour changes. One executable line is touched: the message string
of a unit-test `assert!` that asserted the auto-select claim being
corrected here.

* docs(drm): fix the second primary-CRTC occurrence the audit flagged

Same correction as the enumeration-side comment: libdrmtap auto-selects
the first CRTC with a valid mode, and primary names a plane there. The
audit had flagged both sites and only one was fixed.

* feat(drm): move the libdrmtap pin to 0.5.2 and the ABI gate with it

libdrmtap 0.5.2 is now on rustdesk-org, so the pin can move. It fixes the
padded-framebuffer read: a scanout whose pitch exceeds width*bpp was
decoded at the wrong stride, which is why the Touch Bar strip on an Apple
T2 produced no image and was listed as a known limitation.

The three parts have to land together, and build.py enforces it: the
staged .so is cross-checked against the ABI constants parsed out of
drmtap_dl.rs, so a pin without the gate (or a gate without the pin) fails
the build rather than producing a deb whose capture can never start.

- pin: cbc5e6af5 (0.4.15) -> 653de8c (0.5.2), in build.py, which is the
  single source of truth, plus the informational version comment in
  libs/scrap/Cargo.toml.
- gate: DRMTAP_ABI_MINOR 4 -> 5 and the patch floor (4, 10) -> (5, 0).
  0.4.x is now refused even though it carries the whole split API, because
  of the stride bug above.
- the newer-minor rejection test now derives its cases from
  DRMTAP_ABI_MINOR rather than hardcoding 5, so the next bump cannot leave
  it asserting that the newly verified minor must be refused. That is
  exactly what the hardcoded list would have done here.
- DRM_CAPTURE_SECURITY.md: the vetted window is now 0.5.x with x >= 0.

Verified: the build fetches 653de8c by sha and meson produces
libdrmtap.so.0.5.2, which the runtime gate accepts. Tests 111 in the
rustdesk crate, 20 in scrap.

* fix(drm): refuse --drm on the packaging paths that cannot honour it

Blocking finding from review. `get_features()` gated only on `windows or
osx`, but Linux has four packaging branches and only the deb one is
drm-aware. On a host with pacman, yum or zypper, `--drm` compiled in
`drm,drm-wake` and then packaged through a path that does not bundle
libdrmtap, does not rename, adds no Conflicts/Provides and never runs
`assert_staged_binary_is_drm()` -- emitting a package NAMED `rustdesk`
carrying the consent-bypass backend and the root-side uinput injection.

The distinctly named package is the informed consent this feature rests
on, so those branches now refuse the flag instead. `linux_packaging_branch()`
mirrors the elif chain in main() and is the single place that decides,
so the check cannot silently disagree with the branch actually taken.

Also from the same review:

- the bare-soname dlopen fallback is no longer offered when running as
  root. It exists so an unpackaged development build can load a locally
  built .so, but it was also the one place where which file happens to be
  on the ld.so path decided what gets mapped into the CAP_SYS_ADMIN
  process. The packaged service finds the absolute path first regardless,
  and a root process that reaches the fallback has no bundled library at
  all, which is the PipeWire-fallback case rather than a reason to search.
- `rm -f {so}` is quoted, like the neighbouring `cp` already was.
- `Cargo.lock` is dropped as a CI path trigger. Measured over the last 100
  commits it alone would have fired this workflow 13 times and the pair 24
  times, each about two job-hours of vcpkg + flutter release build, almost
  always for a dependency the drm path never touches.
- `abi_gate_rejects_a_library_from_before_the_split` no longer implies the
  patch floor is what refuses those versions; the minor mismatch is. The
  floor is vacuous by construction while it sits at patch 0 of the
  verified minor, so a second test asserts exactly that and turns into a
  tripwire the next time a floor lands mid-minor, as (4, 10) did.
2026-08-06 12:20:57 +08:00
fufesou
f5ab01f8bd fix(clipboard): win, populate file formats (#15692)
* fix(clipboard): win, populate file formats

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

* fix(clipboard): prevent Windows file clipboard OOB access

* reduce diffs to master

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

* comments

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

* fix(clipboard): win, OOBs and double free

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

* fix(clipboard): win, check deep copy

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

* comments

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

* fix(clipboard): harden Windows clipboard memory handling

- clear HGLOBAL aliases after ownership transfers
- validate callback inputs and capability sets
- bound file-content responses and close search handles on errors

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

* fix(clipboard): harden Windows cliprdr memory safety

- validate clipboard descriptors and response sizes
- fix allocation ownership and cleanup paths
- synchronize format-map access across callback and STA threads
- prevent clipboard format TOCTOU races

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

* Comments on stale remote file formats

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

* fix(clipboard): check pointers before using

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

* fix(clipboard): harden Windows COM error handling

- roll back FORMATETC enumeration on deep-copy failure
- keep the enumerator constructor internal
- propagate IStream seek and read failures

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

* explicity `WIN32_FIND_DATAW`

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

* fix(clipboard): validate format data size and simplify lock cleanup

Reject clipboard data exceeding UINT32_MAX before allocation and
keep format-map cleanup and lock release within the owning function.
Add boundary tests for response data sizes.

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

* fix(clipboard): missing frees

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-08-06 11:16:01 +08:00
Mariano Abad
cc85685b96 fix(linux): stop losing every inhibitor when the ScreenSaver name is absent (#15772)
On Linux, keeping the host awake during an incoming session asks keepawake for
three things at once: the display through org.freedesktop.ScreenSaver on the
session bus, and idle plus sleep through logind on the system bus. keepawake
takes the ScreenSaver one FIRST and abandons the whole request if it fails, and
WakeLock::new discarded the error with .ok(). So on any session where that name
is missing, RustDesk silently holds NOTHING - not the display inhibit it could
not take, and not the logind inhibits it never got to. On a host whose logind
IdleAction is not the default, that means the machine can suspend in the middle
of an active remote session, with any capture backend.

The name is missing on a GNOME login screen. Measured on a GNOME/Wayland GDM
greeter: org.freedesktop.ScreenSaver answers "was not provided by any .service
files" and cannot be activated, while org.gnome.SessionManager is on the same
bus and its idle inhibit works there. Same machine, same state: with it held the
output was still lit at 129.9 s of idle, without it the compositor disabled the
output after 30.3 s. Disabled, not blanked - an idle compositor releases the
CRTC, so there is no scanout left for anything to read.

So on the failure path, take both halves separately instead of neither:
- ask keepawake again without the display part, which restores the logind
  idle/sleep inhibits that have nothing to do with the missing session name;
- and get the display half from whichever session interface this desktop has,
  trying org.gnome.SessionManager and then org.freedesktop.PowerManagement.

Only the failure path changes: a session where the ScreenSaver inhibit works is
untouched. Where no session interface answers, the log now names every one that
was tried and the error each returned, which is the whole diagnostic for a
desktop nobody here can test on.

Verified on a GNOME/Wayland greeter with a live client: the inhibit is taken
86 ms before anything else happens on the connection, and appears to
gnome-session as "RustDesk: incoming session (idle)". The PowerManagement entry
is NOT verified - it is the interface KDE and XFCE implement, it costs one extra
failed call where it is absent, and the log is what will tell us whether it is
the right one.
2026-08-06 10:58:23 +08:00
RustDesk
7eb9150116 Audit retry nonce (#15759)
* fix: retry audit posts and add per-record nonce

A single post_request attempt meant any transient failure (timeout,
DNS, connection reset) silently dropped the audit record. Retry up to
3 times with backoff and log at error level when a record is finally
dropped.

Retries (and the existing TCP-proxy fallback) can deliver the same
record twice; attach a per-record nonce so the api server can dedup.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: fail audit posts on http error status

post_request discards the status code, so a 5xx from a reverse proxy
(e.g. nginx answering 502 while hbbs restarts) or any 4xx rejection was
treated as success and the audit record silently dropped without a log
line. Add post_request_with_status (same semantics and TCP-proxy
fallback as post_request, status preserved; existing callers untouched)
and use it for audit posts: 2xx succeeds, transport errors and 5xx
retry, 4xx fails immediately since retrying a deterministic rejection
cannot help.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: report audit posts rejected with 200 error body

hbbs maps handler failures (e.g. a database write error) to HTTP 200
with an {"error": ...} body (WebError::ServerError), so the client
treated them as success and the audit record was silently dropped.
Detect the error body and fail visibly. No retry: the server already
consumed the nonce, and persistence failures are the server's job to
solve; the client's job is to make the loss visible.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: give audit retries a delay long enough to outlive a restart

The backoff was 1s then 2s, so all three attempts landed within about three
seconds. That does not cover the case the retry exists for: a reverse proxy
answering 502 while the api server restarts fails fast, so every attempt hits
the same outage and the record is dropped anyway.

Use 10s and 30s instead. The window is bounded on the other side - the api
server dedups by nonce for five minutes, and a retry arriving after that
expired would be stored twice - so the worst case is now about three minutes,
leaving room under that limit.

Derive the attempt count from the delay table so the two cannot drift apart.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: retry audit posts the server answered with an error body

hbbs reports handler failures as 200 with an {"error": ...} body, and this
treated them as final on the grounds that the server had already consumed the
record's nonce. That is no longer how the server behaves: it releases the nonce
when the write fails, and answers a post whose earlier attempt is still being
written with an error as well. Both are exactly the cases where trying again is
what gets the record stored, so giving up after the first attempt drops audit
records the retry was added to save.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: bound audit retries by elapsed time, and retry 408 and 429

The comment claimed the retry window fit inside the server's five-minute nonce
memory with room to spare, and that was wrong: one attempt is up to 84s, not
12s, because post_request_ retries the TLS handshake up to four times at 12s
each before the 36s TCP-proxy fallback. Three of those plus the delays is 292s
against a 300s window, and a suspend between attempts stretches the wall clock
without any bound at all, so counting attempts cannot bound this. Stop by
elapsed time instead: no new attempt starts past 120s, which leaves the last
one room to finish well inside the server's window.

Also retry 408 and 429. Both are transient - the request timed out upstream, or
a proxy is shedding load - but the 5xx test dropped the record after the first
attempt.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: only an empty 2xx body counts as a stored audit

The success check was inverted: any 2xx body that failed to parse as an
{"error": ...} object was reported as stored. A proxy interposing a 2xx
maintenance page, or a malformed error value, therefore ended the retry loop
with success and silently dropped the record - the exact loss the retry was
added to prevent.

The audit handlers' success contract is an empty body, so treat exactly that as
success. A nonempty body with a valid error message stays a retryable server
error; any other nonempty body is now a retryable "unexpected response body"
instead of an accepted store. Both old and new hbbs answer success with an
empty body, and no caller reads the returned text, so nothing depends on the
previous acceptance.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: do not start an audit retry past the deadline

The deadline was only checked after an attempt returned, so an attempt could
still begin up to one backoff delay past it - starting as late as ~150s and
landing at ~234s, while the comment claimed no attempt starts past 120s.
Re-check after the delay so the stated bound actually holds: the last attempt
now starts before 120s and lands by ~204s, inside the server's five-minute
nonce window with margin restored.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs: drop a retry rationale the server no longer backs

The comment claimed hbbs answers a post whose earlier attempt is still being
written with an error, so that retrying it is what stores the record. That
stopped being true: hbbs now answers a concurrent duplicate as already stored
rather than as retryable, having dropped the in-flight rejection along with the
claim state machine it needed.

Nothing in the handling changes - a 2xx carrying an {"error": ...} body is
still retried, and that is still right, because the server releases the
record's nonce when its write fails. Only the half of the rationale the server
no longer backs is gone, since this comment is where the contract between the
two repos is written down.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 10:57:09 +08:00
Alex Rijckaert
ef3a57580f Update Dutch translation (#15767)
* Update Dutch translation

* Update src/lang/nl.rs

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-08-05 16:51:07 +08:00
fufesou
402ed07b0c fix: Harden Windows installer temp command scripts (#15634)
* fix: Harden Windows installer temp command scripts

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

* fix: restore stop-service after install preparation failure

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

* fix(windows): preserve special characters in installer paths

Handle carets and exclamation marks safely across cmd.exe parsing stages.
Add coverage for special-character paths in the elevated installer handoff.

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

* fix: installer, validate app name

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

* update tests

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

* Simple refactor

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

* Simple refactor

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-08-04 14:29:04 +08:00
Fadouse
3cf32e7066 fix(wayland): scale portal pointer coordinates on niri (#15683)
* fix(wayland): scale portal pointer coordinates on niri

* perf(wayland): cache portal scaling desktop check
2026-08-04 14:18:41 +08:00
fufesou
6f1eb164d6 fix(clipboard): validate files (#15693)
* fix(clipboard): validate files

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

* fix(clipboard): address file validation review feedback

- remove unreachable empty-prefix test assertions
- name the shared COM/LPT prefix length
- document non-atomic path validation behavior

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

* update hbb_common

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

* fix(clipboard): reject traversal in file descriptors

- reuse parser validation for outgoing descriptor names
- propagate descriptor serialization errors
- add regression coverage for parent path components

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

* fix: clipboard, validate file name length

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

* fix: clipboard, comments

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

* fix(clipboard): support multi-root file selections

Use each top-level path's parent as its relative root so file
descriptors remain safe and relative across different directories.

Add regression coverage for multi-root selections.

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

* fix(clipboard): unix, select multiple items

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-08-04 14:11:27 +08:00
xPrimeTime
4389687d9d fix(wayland): subscribe to portal Response before making the request (#15726)
`request_remote_desktop` and its response handlers call the portal method
first and only then subscribe to the resulting Request's `Response` signal,
using the object path returned by the call. The comment above
`create_session` already describes why that is wrong:

> To avoid a race condition between the caller subscribing to the signal
> after receiving the reply for the method call and the signal getting
> emitted, a convention for Request object paths has been established that
> allows the caller to subscribe to the signal before making the method
> call.

The code then does the opposite of what the comment says. When the portal
emits `Response` before our match rule is installed, the signal is dropped
and the flow stalls: `request_remote_desktop` spins its 3-minute wait loop
and gives up, so the user sees the screen picker again (or a failure) even
when a valid restore token would have restored the session silently.

Build the request path from our unique bus name plus the `handle_token` we
pass in the call arguments, per the Request documentation, and subscribe
before calling. Applied to all five portal calls: CreateSession,
SelectSources (both the ScreenCast and post-SelectDevices paths),
SelectDevices, and Start. The `handle_token` values are unchanged; they are
now named locals so the path and the argument cannot drift apart.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 12:46:09 +08:00
fufesou
a84bad4639 refact(oidc): manually open the browser (#15706)
* refact(oidc): manually open the browser

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

* refact(oidc): allow copying OIDC authentication links

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

* Remove unused translation in ko.rs

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

* refact(oidc): better hint on browser didn't open

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

* refact(oidc): login handle exception

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

* refact(oidc): remove unused translations

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

* refact(oidc): login handle error

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

* refact(oidc): login in flight

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

* refact(translation): move "Continue" to the end of template.rs

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

* refact(oidc): var rename

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

* refact(oidc): remove useless "open sign-in page"

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

* Remove unecessary translation contents

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

* refact(oidc): better way to show&expand the url

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

* refact(oidc): better login ui

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

* fix(oidc): discard stale auth results after cancellation

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

* fix(oidc): handle auth status query failures safely

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

* fix(oidc): prevent concurrent login operations

- reuse the active login dialog and block duplicate password submissions
- cancel only active OIDC operations when closing the dialog
- preserve authentication state until failure cancellation succeeds

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

* fix(oidc): refine login options error feedback

Preserve typed errors to hide the network tip for
HTTP failures and clarify the login-options API contract.

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-08-04 12:35:04 +08:00
RustDesk
e6dd925ab0 fix(android): close outgoing sessions when the task is swiped away (#15753)
* fix(android): close outgoing sessions when the task is swiped away

Swiping RustDesk away from recents destroys the UI but does not
necessarily end the process: when MainService is running (screen share
enabled, or started at boot) the process survives, and with it the
native io_loop of any active outgoing session.

That orphaned io_loop keeps echoing TestDelay (client.rs handle_test_delay
runs entirely on the network thread, no UI involved), which keeps
refreshing last_recv_time on the controlled side. Its 30s inactivity
timeout in server/connection.rs therefore never fires, so the remote
session stays established with no UI left to close it, and the peer
cannot be reconnected to.

Close client sessions from Service.onTaskRemoved, which fires only on
explicit task removal -- not on Home or backgrounding, so ordinary
backgrounding is unaffected. The service itself keeps running, so
incoming connections and the device staying reachable are unchanged.

This complements 152c5c71b, which covered the route-pop path via
dispose(); dispose() does not run when the task is removed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(android): also close sessions on activity destroy

Review follow-up. onTaskRemoved only reaches MainService, but the
accessibility InputService keeps the process alive on its own: a user
with input control enabled and screen sharing off has a surviving
process after a swipe while MainService is not running, so the callback
never fires and the session still outlives its UI. onTaskRemoved cannot
cover that -- InputService is bound by the system, not started, so the
callback is not delivered there.

Close from MainActivity.onDestroy() as well, which runs while the
process is still alive regardless of which service keeps it up. Guarded
on isFinishing so a destroy for recreation (configuration change, "don't
keep activities") does not tear down a live session. Both paths are
idempotent.

Also drop the now-wrong "on task removed" wording from the Rust log,
which has two distinct callers.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(android): release held keys before draining the session map

close_all_sessions drained SESSIONS first, then called
release_remote_keys. The release path sends through get_cur_session(),
which resolves against SESSIONS, so every generated key-up was dropped
after take_remote_keys() had already cleared TO_RELEASE: a key held as
the task is removed stays down on the controlled side until its own
timeout, with the state lost locally.

Release first, while a session is still registered. It is a no-op when
no key is held, so the previous is_empty() guard is not needed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 11:18:14 +08:00
RustDesk
d752823b8c swtich_code for hbbs (#15615)
* swtich_code for hbbs to bypass ACL

* improve register_switch_grant: skip public server, log at error level

Also document why registration is fire-and-forget with no retry: the
peer connects within seconds, so a late retry would land after its
punch request was already rejected; a failed switch is recovered by
the user triggering it again, which registers a fresh grant.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* add timestamp

Signed-off-by: 21pages <sunboeasy@gmail.com>

* fix(switch-sides): handle grant registration clock skew

  - retry registration once with the server-provided timestamp
  - require an explicit accepted response from hbbs
  - report malformed or incomplete responses

Signed-off-by: 21pages <sunboeasy@gmail.com>

* fix(switch-sides): register grants with code verifiers

  - send a derived verifier instead of the raw switch code
  - use detached signatures for grant registration
  - add verifier and signed-message tests

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
Co-authored-by: 21pages <sunboeasy@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-04 11:08:59 +08:00
Stephan Paternotte
2f8822ec7a Update nl.rs (#15754)
* Update nl.rs

Updates plus a small improvement to the Dutch language file

* Update nl.rs

Now including fixes for coderabbit reportings

* Update nl.rs

Three more fixes re. greptile

* Update nl.rs

typo 'loskoppelenn' fixed as well
2026-08-04 10:29:31 +08:00
RustDesk
ffe20bb297 Login options error feedback (#15727)
* fix(flutter): show error and retry when fetching login options fails

The third-party login section of the login dialog was silently hidden
whenever /api/login-options could not be fetched (e.g. TLS handshake
aborted by a router/ISP scam filter, discussion #15700), leaving users
staring at a dialog with no feedback. The pure-Dart HTTP path also had
no timeout, so a black-holed connection could hang indefinitely.

- let transport errors propagate from queryOidcLoginOptions instead of
  swallowing them; a non-JSON response still means "no third-party
  login" so self-hosted servers without this API keep the old behavior
- show network_error_tip, a Retry button, and the underlying error in
  the login dialog so users and supporters can see what failed
- bound the Dart HTTP branch with a 15s timeout; the Rust branch keeps
  its own bounded per-attempt timeouts and is awaited to completion so
  a retry never races the URL-keyed ASYNC_HTTP_STATUS entry of an
  abandoned in-flight request

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(flutter): surface currentUser refresh failures that were only logged

Non-transport failures of the token auto-login (/api/currentUser) -- a
bad HTTP status, a filter's HTML block page, or an error field in the
body -- were only debugPrinted, so the address book / group tabs showed
nothing and offered no retry. Reuse the existing networkError channel
so netWorkErrorWidget shows the error with its Retry button.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(flutter): keep retry row visible with progress while refetching login options

Review follow-ups: clicking Retry used to clear the error and hide the
row with no pending feedback, which could read as a dead click while
the Rust fallback chain runs; keep the row, disable the button, and
show the usual LinearProgressIndicator instead. Also raise the Dart
HTTP branch timeout to 30s so large web address book pulls on slow
links do not newly time out; it still bounds the previously unbounded
hang and stays above the Rust side's 12s per-attempt timeout.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore: update webpki-roots to latest Mozilla root store

0.26.9 -> 0.26.11 (now a forwarding shim over 1.x, used by tungstenite)
1.0.4 -> 1.0.9 (used by reqwest / hyper-rustls / hbb_common)

The 0.26.9 line carried its own root snapshot frozen in early 2025, so
the websocket TLS path was building against a stale bundle.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci: weekly workflow to PR webpki-roots root store updates

webpki-roots is a transitive dependency, so dependabot's cargo version
updates would not cover it. A scheduled job runs cargo update for every
webpki-roots instance in each lockfile and opens a PR when the pinned
Mozilla root snapshot is behind, keeping root store changes reviewable
instead of baking them silently into release builds.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(flutter): hide network tip for server-reported currentUser errors

Review follow-up: when /api/currentUser fails with an error the server
itself reported (an error field in a JSON body, or an unexpected
schema), "Please check your network connection" was misleading. Track
whether the surfaced error came from a server response and skip the
network tip for those; FormatException (a non-JSON body such as a
filter's block page) keeps it, since that still indicates a network or
middlebox problem.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(flutter): close timed-out HTTP clients

* fix(flutter): flag server-reported errors at the throw site

Review follow-up (CodeRabbit). Classifying by `e is! FormatException`
mislabeled ambiguous failures: a middlebox block page returning 200
with valid-but-wrong-shape JSON throws a TypeError from fromJson and
was shown without the check-your-network tip, though it is a network
artifact. Set networkErrorFromServer only at the one site that is
certainly server-reported (an error field in the body); every other
failure keeps the network tip plus the raw error text.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci: serialize webpki-roots update runs, null-delimit lockfile paths

Review follow-up (CodeRabbit). A manual dispatch overlapping the weekly
cron could have an older run force-push over the newer branch state;
queue runs via a concurrency group without cancel-in-progress. Also
iterate lockfiles with git ls-files -z so a path with spaces cannot be
word-split, and keep the loop failing the step on any cargo error.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(flutter): improve login retry feedback

Use the theme primary color for the Retry button and hide stale
error messages while a retry is in progress.

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

* fix(flutter): surface login option response errors

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: fufesou <linlong1266@gmail.com>
2026-08-04 10:19:53 +08:00
RustDesk
a5018a022b chore(ios): remove unused GoogleService-Info.plist (#15752)
Leftover from an abandoned Firebase integration. The file is not
referenced anywhere in the repository and is not listed in
Runner.xcodeproj, so it was never copied into the app bundle. No
Firebase or Google Sign-In pod is present in Podfile/Podfile.lock,
nothing calls FirebaseApp.configure(), Info.plist declares no
REVERSED_CLIENT_ID URL scheme, and on the Dart side both
Firebase.initializeApp() and firebase_analytics stay commented out.

Note the values it held were Firebase client configuration (project
identifiers and a public OAuth client id), which are public by design
and ship inside client binaries -- not secrets. This removes dead
weight, it is not a credential rotation.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 15:55:57 +08:00
Mr-Update
6c69faaa1c Update de.rs (#15733) 2026-08-03 15:47:26 +08:00
Daniel Marschall
b19f1ef76f Add SBOM (Software Bill of Materials) for the EU Cyber Resilience Act (EU CRA) (#15732)
* Update flutter-build.yml to generate SBOM

* SBOM Generation: Also checkout submodules

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-08-03 15:17:05 +08:00
fufesou
807e05ea9a refact(oidc): login with api domain (#15710)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-07-30 18:23:48 +08:00
rustdesk
e0254d997e fix ci 2026-07-30 16:40:56 +08:00
RustDesk
006b9737e4 fix(linux): load librustdesk.so relative to the executable (#15719)
* fix(linux): load librustdesk.so relative to the executable

The runner and the Dart FFI init loaded the core library by bare name,
relying on the runner's $ORIGIN/lib RPATH. Repackaged installs (CachyOS
repo, AUR) can lose that RPATH, making the app fail to start with
"Failed to load librustdesk.so" unless users add the lib directory to
ld.so.conf. Resolve lib/librustdesk.so next to the executable first,
then fall back to the loader search path.

https://github.com/rustdesk/rustdesk/discussions/14407

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(linux): harden bundled librustdesk.so resolution

Address review: bail out when readlink() may have truncated the
executable path, and widen the Dart try block so any failure probing
the bundled library falls back to the loader search path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 16:40:27 +08:00
rustdesk
5aeb4cf945 add zstd to reqwest 2026-07-30 15:28:39 +08:00
rustdesk
c6c53f094a chore(flutter): bump desktop_multi_window to fix the Windows /WX build
The give-up log added in the white-window follow-ups declared a local
named message inside MessageHandler, shadowing its UINT message
parameter. MSVC C4457 plus /WX failed both Windows nightly jobs.
Point the lock at rustdesk_desktop_multi_window#35 which renames it.

https://github.com/rustdesk/rustdesk/actions/runs/30512756157

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 14:19:05 +08:00
RustDesk
e63df74715 fix(linux): make quit_cm actually quit the connection manager (#15718)
quit_gui() ends the process on Windows (std::process::exit) and macOS
(NSApp terminate), but on Linux it calls gtk_main_quit(), which has no
effect in the Flutter connection manager: flutter/linux/main.cc runs
g_application_run() (GtkApplication), so gtk_main() is never called and
the assertion inside gtk_main_quit() just fails.

quit_cm() is the only caller that relies on quit_gui() to end the
process. The main window path in ipc.rs calls std::process::exit(-1)
right after it, and the two remaining call sites are in the Sciter UI,
which is not compiled for flutter builds. So a connection manager
reaching quit_cm() on Linux kept running while no longer serving the
`_cm` ipc endpoint, which also stops the server from reusing it, so the
next connection spawns one more.

NOTE: this is a fallback, not an explanation for the stale processes of
#15698: a client merely disconnecting does not reach quit_cm(), the
Flutter side closes the window instead.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 12:01:05 +08:00
RustDesk
9aeb54cf33 Fix flutter white window forceredraw (#15717)
* fix(flutter/windows): heal the white window left by a resize around the first frame

If the window is resized between the creation of the Flutter surface and
the present of the first frame - which is what the PowerToys FancyZones
option "Move newly created windows to their last known zone" does - the
embedder's resize synchronization enters kResizeStarted and from then on
only presents frames that match the new size. A frame already generated
for the old size is rejected, nothing schedules a matching one, and the
window stays white until a real resize re-enters OnWindowSizeChanged,
which resets the resize target and resends the window metrics. Sciter is
unaffected: it repaints synchronously on WM_PAINT and has no such
handshake. Upstream has no fix (flutter/flutter#159630, open at P3).

Recover with a timer armed at creation and re-armed on WM_SHOWWINDOW
(covers windows created hidden and shown much later, e.g. the connection
manager): until the first frame arrives, kick the engine - first with
the cheap ForceRedraw(), which only helps when no resize is pending (it
is gated on resize_status_ == kDone), then by nudging the Flutter child
window by 1px and back, which re-enters OnWindowSizeChanged and heals
the wedge the same way minimize/restore does. Because the first-frame
callback fires on frame generation even when the present is rejected, a
resize observed before the first frame forces one final child refresh -
in practice nearly every window sees a pre-first-frame WM_SIZE, so this
acts as a cheap unconditional guarantee. Giving up after 5s is logged.

The remote session windows get the same fix in
rustdesk_desktop_multi_window.

https://github.com/rustdesk/rustdesk/issues/6756

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore(flutter): bump desktop_multi_window for the white-window fix

Picks up rustdesk-org/rustdesk_desktop_multi_window#33 (340ca43), the
session-window side of the FancyZones white-window workaround. Only the
resolved-ref of this one dependency is moved; nothing else is upgraded.

https://github.com/rustdesk/rustdesk/issues/6756

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(flutter/windows): drop a dead guard and log where users can see it

Two follow-ups on the force-redraw timer.

The resized_before_first_frame_ guard never discriminated. CreateWindow()
sends a WM_SIZE before it returns, and WM_NCCREATE has already installed the
window pointer by then, so the flag was set during construction - before
OnCreate() even arms the timer - and was therefore always true when the first
frame arrived. Drop the flag and do the final child refresh unconditionally,
which is what the code already did, and say so instead of implying there is an
exceptional case.

The give-up message went to std::cerr, which lands nowhere on the machines
that hit this: main.cpp only attaches a console when the process is started
from one or runs under a debugger. Use OutputDebugString so it is actually
readable with DebugView in the field.

Also note in the comment that the "callback fires on frame generation" premise
is not load-bearing - if it only fired on a successful present, the timer would
simply keep nudging - so the redundancy is not mistaken for duplication and
removed later.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* chore(flutter): bump desktop_multi_window to pick up the follow-ups

Moves the pin from the #33 merge (340ca43) to current master (f8c4fce),
which adds #34: the dead resized_before_first_frame_ guard is gone and the
give-up message goes to OutputDebugString instead of a stderr nobody sees.

Keeps the sub-window fix in step with the runner fix in this branch; without
it the two would ship the same logic in two different states.

Edited by hand, not via pub upgrade - that re-resolves unrelated packages.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 11:15:05 +08:00
lunar-me
3442648afe docs: fix 'lowlevel' spelling to 'low-level' in libs/clipboard/README.md (#15712)
Co-authored-by: pi <pi@m2.local>
2026-07-30 10:32:39 +08:00
lunar-me
8545b5ed98 docs: fix 'gressful' misspelling to 'graceful' in libs/clipboard/README.md (#15713)
Co-authored-by: pi <pi@m2.local>
2026-07-30 10:32:23 +08:00
lunar-me
72c052cb9a docs: fix double space in CODE_OF_CONDUCT.md (#15714)
Co-authored-by: pi <pi@m2.local>
2026-07-30 10:32:07 +08:00
RustDesk
12f2de5959 chore(flutter): point window_manager at the post-revert main (#15709)
The lock still pinned 7d9a674, the commit rustdesk-org/window_manager#8
reverted. Move it to current main (cf4aef0), which carries the reworked
guard for methods called after the toplevel window is destroyed.

Edited by hand rather than via pub upgrade: upgrading re-resolved 17
packages, downgrading some and pulling flutter_test and its leak_tracker
tree in as new entries, none of which belongs in this change.

https://github.com/rustdesk/rustdesk/issues/15703

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 17:09:29 +08:00
rustdesk
a6708f40e7 fix https://github.com/rustdesk/rustdesk/issues/15703 2026-07-29 12:31:40 +08:00
RustDesk
85a5fefab8 fix(windows): prevent ghost and duplicate tray icons (#15689) (#15690)
* docs(agents): require minimally invasive, additive-first patches

Codify the review feedback from the tray ghost-icon fix: fixes should
add self-contained code around existing lines instead of restructuring
them, keep platform-specific logic in src/platform/ with fn-local
imports, and leave only thin one-line hooks in shared files.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(windows): stop duplicate tray icons from piling up (#15689)

`check_process("--tray", ..)` is used to decide whether a tray process
needs to be spawned, but it can miss one that is already running: it
cannot read the command line of an elevated process from a non-elevated
one (the installer spawns the tray elevated), and wmic, used by 32-bit
builds since #11638, is gone from newer Windows 11. `connection.rs` runs
that check once per incoming connection, so every miss added another tray
icon and they kept piling up, which is the same blind spot behind #6692.

Hold a named mutex in the session namespace as the authoritative single
instance guard, so a redundant tray process exits before creating an
icon. `ERROR_ACCESS_DENIED` also counts as "already running", since it
means the mutex belongs to a tray we may not touch.

Also remove the icon before the tray menu's "Stop service" calls
uninstall_service(): on success it ends the process with
std::process::exit, which skips the destructor that would call
Shell_NotifyIcon(NIM_DELETE), so every click left a ghost icon behind.
The icon is shown again if stopping the service failed or was cancelled.

Ghost icons from the taskkill in the install/update/service flows are
left alone here.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(windows): note that update_me's pid lookup can silently find nothing

The pids are matched by command line, which comes back empty for a 32-bit
build reading 64-bit processes (hence the `wmic` fallback of #11638, and
`wmic` is no longer installed by default since Windows 11 24H2) and for a
non-elevated process reading an elevated one. `taskkill` matches by image
name and still works, but the session lists are then empty, so the restore
guard silently restores nothing and the update leaves the user without a
tray icon and main window.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(windows): record the confirmed cause of the duplicate tray icons

Process Explorer output in #15689 pinned it down: run_after_run_cmds()
spawns the tray in the caller's own context, so installing or toggling
the service from a RustDesk that was itself started elevated leaves a
high integrity tray behind, which a medium integrity main window cannot
inspect afterwards. Record where the detection fails exactly, so the next
reader doesn't have to rediscover that the executable path, not the
command line, is what comes back empty.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 12:18:57 +08:00
rustdesk
d412d19872 aligned_u8_vec 2026-07-28 13:38:36 +08:00
rustdesk
4dd8e20392 improve id whitelist login failures 2026-07-28 13:36:35 +08:00
rustdesk
dabdbf73bb improve id wildcast 2026-07-28 00:09:45 +08:00
RustDesk
d6ea170061 Id whitelist (#15586)
* id whitelist

* hbb_common

* Update flutter/lib/common/widgets/dialog.dart

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* support wss:// for web client

Signed-off-by: 21pages <sunboeasy@gmail.com>

* fix: handle ID copying separately and remove whitelist logs

Signed-off-by: 21pages <sunboeasy@gmail.com>

* fix en translation

Signed-off-by: 21pages <sunboeasy@gmail.com>

* fix: check switch-side ID whitelist after login initialization

Signed-off-by: 21pages <sunboeasy@gmail.com>

* track pending 2FA challenge state

Signed-off-by: 21pages <sunboeasy@gmail.com>

* support Unicode IDs in whitelist settings

Signed-off-by: 21pages <sunboeasy@gmail.com>

* refactor: unify client ID resolution

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: 21pages <sunboeasy@gmail.com>
2026-07-27 23:24:32 +08:00
fufesou
eefd22b205 fix(macos): prevent remote keyboard focus leaks (#15629)
* fix(macos): prevent remote keyboard focus leaks

Gate keyboard grabbing on window, tab, lifecycle, and primary focus state.
Release grabs on focus loss or minimize and avoid duplicate grab transitions.

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

* fix: macos, keyboard focus, comments known issue

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

* fix: macos, keyboard, fullscreen space switch

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

* fix: macos, keyboard, focus, relative mouse mode

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

* fix(macOS): preserve local overlay focus during input recovery

Prevent fullscreen and relative-mouse focus recovery from reclaiming
remote keyboard input while a local chat or dialog overlay owns focus.

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

* fix: macos, keyboard, comments trade-off

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-07-26 11:54:01 +08:00
FrederickStempfle
5882346caa fix: validate remote audio channel count (#15673) 2026-07-26 09:04:20 +08:00
FrederickStempfle
b1fad7bbed fix: validate RGBA clipboard dimensions (#15672) 2026-07-26 08:56:22 +08:00
dongrencd
57456f0b52 feat(terminal): add Ctrl and Alt toggles to mobile terminal keyboard (#15532)
* feat(terminal): add Ctrl toggle and Ctrl+X shortcut keys to mobile terminal floating keyboard

Signed-off-by: dongrencd <dongrencd@users.noreply.github.com>

* refactor(terminal): restructure keyboard layout with collapse button

- Move | from Row1 position 3 to Row1 end (aligned with collapse button)
- Remove ~ from Row2, add collapse button (∨/∧) after PgDn
- Row3: conditional render, add ~ and -, remove trailing placeholders
- Collapse state persisted via kOptionEnableShowTerminalCtrlKeys
- Row3 defaults to collapsed for compact layout

Signed-off-by: dongrencd <dongrencd@users.noreply.github.com>

* fix(terminal): restore trailing placeholders in Row3 for alignment

Row3 needs trailing placeholders to match Row1/Row2 width (348px)
so Ctrl aligns with Tab in Row2 and Esc in Row1.

Signed-off-by: dongrencd <dongrencd@users.noreply.github.com>

* fix(terminal): update mobile keyboard layout per review

Signed-off-by: dong.ren.cd <dong.ren.cd@tcl.com>

* fix(terminal): address mobile keyboard review regressions

Signed-off-by: dong.ren.cd <dong.ren.cd@tcl.com>

* fix(terminal): preserve ctrl-j newline mapping on mobile

Signed-off-by: dong.ren.cd <dong.ren.cd@tcl.com>

* fix(terminal): preserve pasted input with modifiers

Signed-off-by: dong.ren.cd <dong.ren.cd@tcl.com>

* fix(terminal): harden mobile modifier and paste input

Signed-off-by: dong.ren.cd <dong.ren.cd@tcl.com>

* fix(terminal): harden mobile paste shortcut handling

Signed-off-by: dong.ren.cd <dong.ren.cd@tcl.com>

* fix(terminal): preserve unicode graphemes under ctrl

* fix(terminal): avoid modifier scan for inactive locks

* fix(terminal): keep default hardware paste shortcuts

* fix(terminal): guard hardware paste with modifier locks

* fix(terminal): update mobile key button color role

---------

Signed-off-by: dongrencd <dongrencd@users.noreply.github.com>
Signed-off-by: dong.ren.cd <dong.ren.cd@tcl.com>
Co-authored-by: dongrencd <dongrencd@users.noreply.github.com>
Co-authored-by: dong.ren.cd <dong.ren.cd@tcl.com>
2026-07-25 22:33:16 +08:00
21pages
cefff781d4 feat(recording): add visibility and service storage options (#15662)
* feat(recording): add visibility and service storage options

  - support hide-recording-button in Flutter and Sciter
  - allow a custom save directory for Windows service recordings
  - sanitize peer IDs used in recording filenames

  Tested:
  - with hide-recording-button=Y and allow-auto-record-outgoing=Y,
    outgoing sessions are recorded automatically while the recording button
    remains hidden and cannot be stopped from the UI; verified on Flutter
    desktop, Sciter, and Android
  - windows-service-video-save-directory takes effect when the Windows client
    runs as an installed service
  - the Windows controlling side can save recordings for direct IP:port
    connections

Signed-off-by: 21pages <sunboeasy@gmail.com>

* update hbb_common

Signed-off-by: 21pages <sunboeasy@gmail.com>

* fix(recording): validate configured save directories

  - trim configured recording directory paths
  - reject non-absolute paths and fall back to defaults
  - warn when a non-empty path is invalid

Signed-off-by: 21pages <sunboeasy@gmail.com>

* fix(recording): validate configured save directories

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-07-25 15:21:13 +08:00
fufesou
ad9dac1001 fix(keyboard): jis, macos, muhenkan henkan (#15669)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-07-25 09:36:25 +08:00
CHarris
b4af82157b fix: refresh wayland uinput range on compositor layout change (#15628)
* fix: refresh wayland uinput range on compositor layout change

The uinput absolute range is computed once at session init. If the
compositor layout changes mid-session (monitor scale or position
change, or a portal virtual output appearing once capture starts),
injected coordinates are rescaled by the stale range and land offset.

Poll the live desktop bounding box from the display service loop while
subscribed (one wayland roundtrip, throttled to 1.5s, no subprocesses)
and re-apply the uinput resolution when it changes. Also read a fresh
layout when computing the initial range in check_init, since the cache
is not cleared when a session closes through the restore-token path.

This is the X component of #15601. The stale advertised origins (the Y
component) are not touched here: re-advertising DisplayInfo mid-session
trips the portal re-negotiation and can drop displays.

Signed-off-by: Cody Harris <codyharris7188@gmail.com>

* fix: bound the mouse resolution IPC wait during session init

Wrap update_mouse_resolution in the same 3s timeout the periodic
refresh uses, so a hung IPC response can't stall check_init.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: build timeout future inside runtime, split linux lazy_static

Constructing the timeout future eagerly as the block_on argument panics
with 'there is no reactor running'; move it into the async block so it is
built inside the runtime context. Also move WAYLAND_UINPUT_RECT into its
own cfg-gated lazy_static block, an attribute on a single item inside the
shared block does not compile.

* fix: confirm uinput mouse device adopted new range before caching rect

send_refresh() now waits for the mouse service to ack that it recreated the
device with the new range instead of firing and forgetting, and
update_mouse_resolution() propagates that result. The layout poller only
caches the rect after the device actually adopts the range, so a failed
refresh errors and retries on the next check. The ack read is bounded by
IPC_REQUEST_TIMEOUT, matching the keyboard get-key-state path.

* fix: propagate refresh failures instead of caching a stale range

- input_service: error when the custom-mouse downcast fails so the poller
  retries instead of caching an unconfirmed refresh
- uinput: on device recreation failure, keep the current device and the
  IPC connection and withhold the ack so the client retries, instead of
  killing the mouse handler

* fix: remap injected wayland coords onto the live layout after a monitor moves

The range refresh corrects the uinput ABS bounds, but a single-display client
sends whole-desktop coordinates offset by the origin of the display it follows,
taken from the layout advertised at session init. When another monitor is
rescaled or moved that origin shifts, so the coordinate lands offset before it
reaches uinput and the range refresh cannot recover it.

Snapshot the per-display layout at init, poll the live layout on the existing
1.5s throttle, and when they differ remap each injected move into the followed
display's current rectangle (matched by connector name, index fallback when the
compositor reports none). No-op and lock-free while the layout is unchanged.

---------

Signed-off-by: Cody Harris <codyharris7188@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 18:35:49 +08:00
21pages
beaa754299 fix stale primary display selection (#15460)
* fix stale primary display selection

Signed-off-by: 21pages <sunboeasy@gmail.com>

* fix stale display selection during login and switching

  - resolve the primary display from the refreshed login snapshot
  - defer display enumeration until authentication succeeds
  - read Wayland displays and primary index from the same cache snapshot
  - reject stale monitor and camera indices during display switching

Signed-off-by: 21pages <sunboeasy@gmail.com>

* fix inconsistent display snapshots during login

  - return displays from the same enumeration used to select the primary
  - avoid re-reading the shared display cache after updating it
  - use the same converted snapshot during Wayland initialization

Signed-off-by: 21pages <sunboeasy@gmail.com>

* avoid cloning unchanged display snapshots

Signed-off-by: 21pages <sunboeasy@gmail.com>

* fix invalid display subset handling

Signed-off-by: 21pages <sunboeasy@gmail.com>

* minimize code churn in switch_display_to

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-07-23 17:17:01 +08:00
bmmh1
929e989f17 feat(macos): silent auto-update with security hardening (#15550)
Co-authored-by: bmmh1 <bmmh1@users.noreply.github.com>
2026-07-23 00:22:10 +08:00
hatterp
1c2dd71891 Translate 'Continue' to 'Kontynuuj' in Polish (#15641) 2026-07-21 22:43:09 +08:00
Kuksgauzen
5b4d6baf47 fix: wrap BackingScaleFactor in autoreleasepool to stop NSDictionary accumulation on macOS (#15623)
Signed-off-by: Viktor Kuksgauzen <vkpiar@gmail.com>
2026-07-21 05:42:43 +08:00
gateslu
7696b0ee51 fix(linux): forward forced display server to user server (#15627)
Signed-off-by: Gateslu <lyjbbq@163.com>
2026-07-20 13:24:48 +08:00
CHarris
20ab5ab0ad fix(deploy): don't wipe local id when --deploy gets an empty --id (#15633)
`rustdesk --deploy --id ""` (e.g. an unset variable in a deployment
script) deploys a blank id, then wipes the local id and unconfirms the
key through the IPC config write. The Android deploy flow already guards
an empty id (#15146); apply the same guard to the CLI, and reject an
empty id at the IPC write boundary the same way the read path was fixed
in #15626.
2026-07-20 10:58:28 +08:00
CHarris
c01300be20 fix(ipc): never adopt an empty id from the main IPC (#15626) 2026-07-20 10:22:46 +08:00
cui fliter
5f015c9da1 Translate Continue into Simplified Chinese (#15621)
Signed-off-by: cuishuang <imcusg@gmail.com>
2026-07-18 17:56:27 +08:00
RustDesk
082a5a2a4e Revert "Fix Adjust Window sizing across DPI (#15592)" (#15620)
This reverts commit 61f0944990.
2026-07-18 16:37:30 +08:00
21pages
61f0944990 Fix Adjust Window sizing across DPI (#15592)
* Fix Adjust Window sizing across DPI and fullscreen transitions

Signed-off-by: 21pages <sunboeasy@gmail.com>

* Use visible screen frame for Adjust Window

Signed-off-by: 21pages <sunboeasy@gmail.com>

* Tolerate floating-point errors in Adjust Window sizing

Signed-off-by: 21pages <sunboeasy@gmail.com>

* Fix review, fix Adjust Window async metric guards

Capture the current screen before awaiting window geometry so one target-frame calculation uses consistent screen metrics.

Return early when adjusting without a context and the Flutter view list is empty, instead of calling views.first after the window or engine may have been torn
    down.

Clarify the platform coordinate units used for Adjust Window scaling.

* Fix Adjust Window for maximized Linux windows

Unmaximize Linux remote windows before applying Adjust Window because native setFrame may be ignored while the window is maximized.

* Fix Adjust Window screen refresh guards

Refresh screen metrics before checking Adjust Window availability and again after exiting fullscreen so target-frame calculation uses current window geometry.

Hide Adjust Window on web because resizing relies on desktop window APIs.

* Fix review, handle missing window frame in Adjust Window

Return null when WindowController.getFrame fails so Adjust Window availability checks and resize attempts skip cleanly if the window is hidden or disposed.

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-07-18 16:32:58 +08:00
21pages
96e2a330b8 restrict switch sides to remote desktop sessions (#15610)
* fix: restrict switch sides to remote desktop sessions

 Reject switch sides requests outside authenticated remote desktop sessions, and reject switch sides responses that try to carry non-remote login types.

 Add scope coverage so file transfer, terminal, view camera, and port forward sessions cannot use switch sides.

Signed-off-by: 21pages <sunboeasy@gmail.com>

* fix review: consume switch sides UUID before rejecting response

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-07-17 15:52:49 +08:00
21pages
5abf4e9724 Fix disabled installation bypass (#15598)
* Fix disabled installation bypass

Prevent install.exe and --install from opening the install flow when disable-installation is set.

Signed-off-by: 21pages <sunboeasy@gmail.com>

* Refine disabled installation handling for portable clients

Document why --install must be filtered from both Rust and Flutter runner arguments for portable wrappers such as no-install.exe. Remove redundant UI-
    layer installation checks because the install entry points are already gated upstream.

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-07-16 16:00:38 +08:00
jinqiang zhang
cf2b28faf9 fix linux llvm22 build (#15565)
bindgen-0.65 is incompatible with llvm 22, we should upgrade to a
newer bindgen version

error message:

```
error[E0609]: no field `g_w` on type `vpx_codec_enc_cfg`
  --> libs/scrap/src/common/vpxcodec.rs:66:19
   |
66 |                 c.g_w = config.width;
   |                   ^^^ unknown field
   |
   = note: available field is: `_address`
```
2026-07-15 13:27:15 +08:00
fufesou
bdb38c4730 fix: check valid id (#15535)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-07-14 15:35:52 +08:00
Maison da Silva
fa418cace6 Translate 'Continue' to 'Continuar' in ptbr.rs (#15567)
Translate 'Continue' to 'Continuar' in ptbr.rs
2026-07-13 18:56:41 +08:00
rustdesk
94a2a2bb4a fix https://github.com/rustdesk/rustdesk/issues/15566 2026-07-11 21:43:04 +08:00
Maison da Silva
865fe71c46 Update Portuguese translations for clarity (#15534) 2026-07-11 17:18:12 +08:00
rustdesk
137298e05a revert back 2026-07-10 15:21:48 +08:00
rustdesk
685a89a171 target Android 15 2026-07-10 15:12:06 +08:00
RustDesk
12b5cc7f72 Revert "fix: ci: macos: allow signed but not notarized dmg (#15530)" (#15551)
This reverts commit 29e1852a68.
2026-07-10 11:47:13 +08:00
Vasyl Gello
480e9e8234 Fix default Android API version mismatch between vcpkg and rest of build (for working on android 6) (#14850)
* Fork vcpkg triplets to keep Android API version on 21

Fixes crash on API platforms 21 to 23 due to missing
symbol `__write_chk` (available since API 24).

Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>

* flutter/build_android_deps.sh: Refactor to remove unused

... variables and shellcheck warnings.

Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>

---------

Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2026-07-10 11:38:43 +08:00
Zhenyu FU
29e1852a68 fix: ci: macos: allow signed but not notarized dmg (#15530)
* fix: ci: macos: allow signed but not notarized dmg
Signed-off-by: Zhenyu FU <ysfcore@outlook.com>

* fix: ci: macos: add pre-check for macos identity
Signed-off-by: Zhenyu FU <ysfcore@outlook.com>

* merge notarize checking to existing steps
Signed-off-by: Zhenyu FU <ysfcore@outlook.com>
2026-07-09 15:23:43 +08:00
fufesou
8314335b31 fix: update download, force tls (#15529)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-07-09 15:05:49 +08:00
bovirus
acb9f63e1d Update it.rs (#15531) 2026-07-08 16:35:34 +08:00
VenusGirl❤
005a8b4a04 Update Korean (#15525)
Updated Korean translations for clarity and accuracy.
2026-07-08 11:09:39 +08:00
RustDesk
e2149974cc harden wf_cliprdr.c (#15515)
* harden wf_cliprdr.c

* fix copilot review

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix review

* fix review

* condense hardening comments, fix style in wf_cliprdr.c

Comment-only cleanup of the review-justification comments; also move
the mutex wait result declaration to the top of the block and fix
continuation-line indentation. No behavior change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* add invariant tests for file contents request/response hardening

Cover the zeroed optional request fields, stream ID filtering,
oversized/NULL response rejection and the zero-byte EOF path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* address copilot review findings in wf_cliprdr.c

- Reject a negative FILECONTENTS_SIZE result: m_lSize is unsigned, so a
  negative value became a huge bogus stream size that keeps reads going.
- Use a unique per-stream counter as the CLIPRDR streamId instead of a
  truncated IStream pointer, which could collide or be reused after free
  (and leaked heap addresses to the peer).
- Add req_f_request_mutex to serialize whole file-contents request/response
  cycles, enforcing the previously assumed one-outstanding-request
  invariant when multiple streams are read concurrently. Bounded acquire
  so a wedged request fails the read instead of hanging a consumer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* serialize file-contents request state and poison streams after timeout

- Extract lock_mutex() for the WAIT_OBJECT_0/WAIT_ABANDONED idiom shared by
  take_req_fdata, the request-serialization acquire, and the response handler.
- Collapse the acquire/send/take/release cycle into
  cliprdr_request_filecontents_sync(), used by CliprdrStream_Read and the size
  probe in CliprdrStream_New.
- Publish req_f_stream_id_expected/req_f_size_requested under req_f_mutex in the
  sender and read them under the same lock in the response handler, removing the
  cross-thread data race on those fields.
- Poison a stream (m_failed) after a request fails/times out, so a late response
  carrying a previous offset's bytes cannot satisfy a later same-stream read.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* key the responder stream cache on connID as well as streamId

Per-stream ids restart from 1 in each peer process, so two connections can
emit the same streamId. The process-static pStreamStc cache keyed only on
streamId could then serve one peer the IStream cached for another peer (a
different file), silently returning wrong-file bytes. Add connID to the key.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* harden the format-data path against late/duplicate responses

The format-data rendezvous had the same single-slot race the file-contents
path just fixed: the channel thread rewrote clipboard->hmem with no lock while
explorer-thread consumers read/freed it, nothing serialized concurrent
requests, and no flag told an expected response from a stray one.

- Add format_request_mutex (serializes the whole request/response cycle) and
  hmem_mutex (guards the hmem hand-off and formatDataRespExpected).
- cliprdr_send_data_request now takes ownership of the response buffer under
  hmem_mutex and returns it to the caller, so a later response cannot touch a
  buffer a consumer is using. All three consumers (GetData, WM_RENDERFORMAT,
  DELAYED_RENDERING) and the WM_CLIPBOARDUPDATE cleanup use the returned/taken
  handle instead of the shared slot.
- The response handler drops any response arriving while formatDataRespExpected
  is clear (late/duplicate/unsolicited), consumes the flag on the first
  response, and no longer dereferences a NULL clipboard in the SetEvent path.

Pre-existing issue, not introduced by this branch; generalizes the
file-contents hardening to the format-data path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* remove the dedicated wf-cliprdr CI workflow

Drop .github/workflows/wf-cliprdr-ci.yml on this branch as requested.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* remove wf-cliprdr invariant tests

Drop tests/test_invariant_wf_cliprdr.c on this branch as requested.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor and simplify, remove mutex which is dangeours

* fix copilot false report

* fix review

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 14:54:22 +08:00
rustdesk
6c578292e8 bump to 1.4.9 2026-07-06 18:00:39 +08:00
fufesou
28930c0463 fix: non-E2EE show dialog (#15514)
* fix: non-E2EE show dialog

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

* fix: build web, bridge

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

* fix: direct IP access, do not snow non-E2EE dialog

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

* fix: non E2EE dialog, update contents

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

* fix: non-E2EE, show dialog, port forward

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

* fix: non-E2EE dialog, port forward, ignore direct IP access

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

* fix: non-E2EE is_direct_ip_access()

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

* Simple refactor

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

* fix: non-E2EE dialog, port forward, close socket on disconnect

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

* fix: non-E2EE dialog, incorrect reuse of Data::Close

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-07-06 17:05:11 +08:00
fufesou
37141afece refact: remove feature cli (#15524)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-07-06 16:17:32 +08:00
fufesou
493b14ba78 Fix/session scope permission audit (#15469)
* fix: enforce session-scoped permissions

Restrict non-remote sessions to their allowed message types, filter
out-of-scope login options, and audit rejected or filtered messages.
Hide screenshot controls outside default remote sessions.

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

* fix: typo

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

* fix: prevent privacy mode in view-camera sessions

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

* fix: switch display, check non-view-camera

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

* fix: avoid sending unsupported messages

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

* fix: session scope, add option to control close/alarm

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

* Fix: scoped session handling for view-camera compatibility

  - Skip view-camera auto-login and display-management side effects
  - Allow harmless render broadcasts without affecting non-video sessions
  - Keep legacy view-camera management messages compatible as no-ops
  - Preserve stricter scope violations for non-video session types

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

* update libs/hbb_common

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

* fix: ignore repeated login request

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

* fix: view camera, support "Take screenshot"

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

* fix: session scoped messages, check update options

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

* fix: session scope, check portforward before conn type voolations

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

* fix: scoped messages, reduce changes.

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

* fix: session scope, comments

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

* fix: keep scoped sessions compatible with render broadcasts

Allow legacy render-broadcast no-op messages for file transfer and terminal
sessions while keeping port forward and mixed options scoped. Also avoid sending
new render updates to non-video Flutter sessions.

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

* fix: scope screenshot requests by video source

Key screenshot requests by video source and display index so camera and
monitor sessions cannot consume each other's requests. Deduplicate the Flutter
render-target predicate while keeping render updates limited to video sessions.

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

* fix: Harden scoped session message handling

Filter option updates by authenticated connection type,
keep legacy no-op messages compatible, and avoid noisy repeated
scope violation alarms.

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

* fix: session scope, comments

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

* fix: Send close reason for scoped session violations

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

* fix: Enforce scoped session message filtering

  - filter out-of-scope messages for limited session types
  - scope option updates by authenticated connection type
  - keep render-broadcast no-op compatibility for non-video scoped sessions
  - restore view-camera screenshot handling
  - improve session scope violation audit labels
  - avoid cloning option messages on the remote hot path

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

* Fix scoped session clipboard broadcast compatibility

Treat text clipboard broadcasts as no-op compatibility messages for FileTransfer and Terminal sessions, matching existing
handler behavior and preventing optional scope-violation close from disconnecting those sessions. Keep ViewCamera and
PortForward clipboard messages subject to normal scope enforcement.

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

* fix: log warn

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

* fix: restrict Flutter clipboard sync to default sessions

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

* fix: session scope, comments and tests

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

* fix: session scope, reset sessions in login handle

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

* fix: session scope, view camera, allow clipboard noop

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-07-05 23:28:32 +08:00
StealUrKill
cf1de4de62 Feature: Restore the last viewed monitor on auto reconnect (#15441)
* Feature: Restore the last viewed monitor on auto reconnect

Remembers the users last manually selected remote monitor and returns to it after an auto reconnect.

In memory, reconnect only, and bounds checked against the current display count.

It is skipped in "use all my displays" mode.

Signed-off-by: StealUrKill <35749471+StealUrKill@users.noreply.github.com>

* Address review on reconnect monitor restore

Avoid a crash if the session closes during a reconnect.

Don't overwrite the remembered monitor on auto restore.

Defer the switch until the view is ready so a monitor with a different size renders correctly.

Signed-off-by: StealUrKill <35749471+StealUrKill@users.noreply.github.com>

* Guard all-displays reconnect restore against empty display list

* Harden reconnect monitor restore against races and multi-UI sessions

Cancel a queued restore when the user manually selects a monitor, so a
newer choice is not overridden by a stale pending restore.

Compare the remembered monitor against the reconnect event's display
instead of the stale _pi.currentDisplay, which is intentionally left
unchanged when the peer has multiple sessions.

Add a frame-independent fallback so a multi-UI tab that never receives
the first-image event (its display is filtered to the owning tab) still
restores the remembered monitor.

Signed-off-by: StealUrKill <35749471+StealUrKill@users.noreply.github.com>

* Harden reconnect monitor restore: fallback timer, lifecycle, cursor

Follow-up hardening on the auto-reconnect monitor restore:

- Cancel the fallback timer synchronously once this tab owns the restore,
  so it can no longer fire while onEvent2UIRgba is awaiting canvas setup
  and switch displays before the canvas is ready (the offset the deferred
  restore exists to avoid). The multi-UI no-frame fallback stays intact.
- Apply the restore in a finally so a throwing canvas init still runs it
  instead of stranding a queued restore with the timer already cancelled.
- Cancel the fallback timer on a manual monitor switch, so a newer user
  selection supersedes a queued restore instead of racing it.
- Restore with updateCursorPos: false, matching other programmatic
  display switches so an auto-restore does not reposition the cursor.

---------

Signed-off-by: StealUrKill <35749471+StealUrKill@users.noreply.github.com>
2026-07-05 22:32:47 +08:00
fufesou
9fdb8410d3 fix: parse exit code of flutter web (#15501)
* fix: parse exit code of flutter web

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

* fix: exit-code, debug print

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-07-03 12:49:32 +08:00
alonginwind
a2b79462ab fix: auto-close terminal tab/window when shell exits (#15448) 2026-07-02 16:43:27 +08:00
fufesou
dce221be5a fix(clipboard): make CLIPRDR format-map growth checked (#15493)
* fix(clipboard): make CLIPRDR format-map growth checked

The Windows CLIPRDR format-list handler relies on map_ensure_capacity()
while processing peer-provided formats. The previous helper only attempted
growth: if realloc() failed, it returned silently and the caller continued
processing. A later iteration could then index past the allocated
format_mappings array.

Make format-map growth a checked operation. The handler now validates the
peer-provided format count, ensures the mapping array is large enough before
writing entries, and aborts processing if growth fails. Newly allocated slots
are zeroed so existing cleanup can safely run after partial processing.

Also bound remote format names before measuring/converting them. The chosen
limits follow Windows clipboard/atom constraints:
  - registered clipboard format IDs use 0xC000..0xFFFF
  - string atom names are limited to 255 bytes

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

* fix(clipboard): reject invalid remote format-list entries

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-07-02 16:18:07 +08:00
rustdesk
9d1ab3fba3 fix the AOM tile-control argument type 2026-07-01 11:47:08 +08:00
rustdesk
b3bd18845d update hbb_common 2026-06-30 11:29:56 +08:00
rustdesk
435f6ec61d update copyright 2026-06-30 11:02:28 +08:00
21pages
0497814004 Add authentication details to connection audit (#15456)
* Add authentication details to connection audit

Signed-off-by: 21pages <sunboeasy@gmail.com>

* rename normalize_conn_audit_primary_auth to normalize_conn_audit_auth_fields

Signed-off-by: 21pages <sunboeasy@gmail.com>

* Merge permanent password audit methods

Signed-off-by: 21pages <sunboeasy@gmail.com>

* Simplify connection audit auth methods

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-06-29 16:04:24 +08:00
劉清揚
4b1ef9e20d fix(android): sync input service state with Flutter (#15419)
Signed-off-by: liuqiang <2465199797@qq.com>
2026-06-29 15:14:34 +08:00
twprh
10d5250d23 Update flutter-build.yml (#15454) 2026-06-28 17:18:41 +08:00
Maison da Silva
2ee580d49d Update translation for outdated installation message (#15427)
Update translation for outdated installation message
2026-06-28 12:11:03 +08:00
fufesou
4a54029cac fix(update): msi, norestart (#15440)
* fix(update): msi, norestart

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

* fix(update): escape path

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-27 16:45:27 +08:00
fufesou
001848bf2f fix(fuse): umount (#15426)
* fix(clipboard): clean up stale Linux FUSE mounts

Recover Linux file clipboard FUSE mount points before remounting and stop treating a cached
context as valid when the mount has already gone away.

This fixes the desktop file manager copy failure that shows dialogs such as
"Error while copying a" and "There was an error copying the file into xxx".

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

* fix(clipboard): fuse, reduce dups

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

* fix: clear Linux file clipboard before unmounting FUSE

Ensure Linux client teardown clears RustDesk file clipboard URLs while
the FUSE context is still available. Also prefer fusermount before
umount to avoid noisy unprivileged teardown attempts.

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

* fix(clipboard): return and log errors

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-26 16:17:44 +08:00
21pages
989bf80fe8 Support controller user attribution in audit logs (#15407)
* Support controller user attribution in audit logs

This PR supports associating audit logs with the controller user.

  ## Implementation:
  - Add `ControlledContext { conn_audit_token }` to `PunchHole`, `RequestRelay`, and `FetchLocalAddr`.
  - The server sends a controller-user identity snapshot to the controlled client through rendezvous messages.
  - The controlled client sends the token back to the server when posting the `on_open` conn audit or IP whitelist alarm audit.
  - This lets the server attach the controller user to audit logs.

  ## How the controlled client helps identify the controller user:
  - Conn audit: sends the token to the server in `on_open`; the server creates the audit log and caches the user snapshot.
  - File audit: sends `id` and `conn_id`; the server uses them to find the cached user snapshot.
  - Alarm audit: IP whitelist sends the token directly; other alarm logs send `id` and `conn_id`, and the server uses them to find the cached user
  snapshot.

  ## Compatibility:
  - Supported only for logs created with a new server and a new controlled client.
  - Does not require upgrading the controller client.

  ## Test

  - [x] New/old clients connected to new/old servers, and conn/file/alarm audit logs worked normally.
  - [x] New client connected to new server generated searchable conn/file/alarm audit logs.
  - [x] Punch hole, local addr, and relay paths worked with audit logs and control role on new/old servers.
  - [x] Direct IP connections produced audit logs, but do not support user audit.

Signed-off-by: 21pages <sunboeasy@gmail.com>

* rename conn_audit_token to conn_audit_ref

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-06-26 15:07:27 +08:00
VenusGirl❤
78b5f47668 Update ko.rs (#15395) 2026-06-26 13:51:08 +08:00
jkh0kr
97e9e44faa Update ko.rs (#15390)
Incorrect translation
2026-06-26 11:19:18 +08:00
RAIT-09
ff226f6d80 fix(clipboard): unix, refresh cached file size/mtime on re-copy (#15392)
* fix(clipboard): unix, refresh cached file size/mtime on re-copy

sync_files() deduped re-copies by path string only, so editing a file
and re-copying it (same path) skipped refreshing the cached size/mtime
and the file-group descriptor; the peer then received the file
truncated to the old cached size (silent corruption for PDF/zip/pptx).
Widen the early-return guard to also compare a top-level (size, mtime)
fingerprint and to always rebuild when a directory is selected. The
Windows wf_cliprdr.c path re-stats per request and is unaffected.

Signed-off-by: RAIT-09 <51452399+RAIT-09@users.noreply.github.com>

* opt(clipboard): unix, compute file fingerprint once and pass into sync_files

fingerprint() was computed before taking the CLIP_FILES lock and then
recomputed inside ClipFiles::sync_files under the lock. Pass the precomputed
value in so the top-level stat runs once and outside the critical section.
No behavior change.

Signed-off-by: RAIT-09 <51452399+RAIT-09@users.noreply.github.com>

---------

Signed-off-by: RAIT-09 <51452399+RAIT-09@users.noreply.github.com>
2026-06-25 09:50:33 +08:00
Daniel Marschall
0cbdb6ffb3 Fix tray icon click (regression due to breaking change in tray-icon 0.17) (#15413) 2026-06-25 09:43:04 +08:00
fufesou
b8117c5c34 fix(fuse): fuse path broken, since ipc path changed (#15406)
* fix(fuse): fuse path broken, since ipc path changed

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

* fix(fuse): init, handle error

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

* fix(fuse): unmount attempt on newly created directory failed

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-24 16:52:27 +08:00
Maison da Silva
a69614d464 Update translation for 'Control Actions' in ptbr.rs (#15386) 2026-06-24 12:26:36 +08:00
fufesou
58ee593e26 fix(custom-client): show options, incoming-only (#15394)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-24 00:26:09 +08:00
fufesou
09bc9056c9 fix(update): win aarch64 (#15389)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-23 17:59:29 +08:00
fufesou
0c6df924d1 refact: file transfer, do this for all conflicts(tasks) (#15385)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-23 11:23:42 +08:00
dependabot[bot]
456817b4f4 Git submodule: bump libs/hbb_common from e50ac3c to 387603f (#15384)
Bumps [libs/hbb_common](https://github.com/rustdesk/hbb_common) from `e50ac3c` to `387603f`.
- [Release notes](https://github.com/rustdesk/hbb_common/releases)
- [Commits](e50ac3cd48...387603f47c)

---
updated-dependencies:
- dependency-name: libs/hbb_common
  dependency-version: 387603f47cbb15c0d3dc3d67ae3396d3eb707daf
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-23 10:28:08 +08:00
rustdesk
16570ee34f fix https://github.com/rustdesk/rustdesk/discussions/15355 2026-06-22 22:57:08 +08:00
just-some-tall-bloke
2b40c61d8e Fix spelling and grammar errors in comments (#15370)
- dbus.rs: fix grammar (add 'between', pluralize 'processes')
- win_impl.rs: fix typo 'hight' -> 'high', idiom 'such called' -> 'so-called'
- startwm.sh: fix typo 'loging' -> 'logging'
- lib.rs: fix copy-paste error in doc comments for scroll buttons
- message.proto: fix typo 'Clipobard' -> 'Clipboard'
2026-06-22 15:26:51 +08:00
RustDesk
dcc64cdeae cjk (#15379) 2026-06-22 14:47:12 +08:00
RustDesk
2747d3d8b4 Revert "fix(arm64-linux): fix CJK font rendering on flutter-elinux (#15324)" (#15377)
This reverts commit c9391fb894.
2026-06-22 13:40:39 +08:00
fufesou
3c574a4182 fix(wayland): clipboard, support ext-data-control (#15366)
* fix(wayland): clipboard, support ext-data-control

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

* fix(clipboard): restart stale listener and log join panics

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

* update clipboard-master

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

* refactor(clipboard): remove redundant stale listener cleanup

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-21 17:09:41 +08:00
Tigah
311d4708e5 fix(linux): reap a crashed headless session's leftovers on next start (#15348)
The teardown cleanup added for #15183 only runs on a clean disconnect.
If the service or its --server crashes before then, the headless logind
session scope and the /tmp/.X<n> lock files it created leak the same way
#15183 leaked them, with nothing to reclaim them afterwards.

Record the session scope and display when the headless session starts,
and on the next --server start reap exactly what the previous run
recorded, then drop the marker. It only ever touches the one scope and
display the previous run recorded, never a scan, so unrelated sessions
are untouched; the reap and X cleanup reuse the teardown path.

A logind session id is only unique within a boot: the counter lives in
/run and resets, so a recorded "session-N.scope" can name a different,
live session after a reboot. Tag the marker with the boot id and only
reap the scope when it matches the current boot. A leaked cgroup cannot
outlive a reboot, so nothing legitimate is lost cross-boot; the X lock
cleanup stays pid-guarded and runs either way.

Signed-off-by: TBX3D <88289044+TBX3D@users.noreply.github.com>
2026-06-21 16:56:41 +08:00
Maison da Silva
5cf4323d07 Fix Portuguese translations for consistency (#15354) 2026-06-21 16:52:28 +08:00
bovirus
3976701ac6 Update Italian translations (#15367) 2026-06-21 16:52:13 +08:00
fufesou
9ded8d6ab2 fix(keyboard): win, key, Pause (#15351)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-20 21:11:19 +08:00
rustdesk
cd2fff0655 fix hbb_common 2026-06-20 18:31:42 +08:00
rustdesk
10f61ffdc2 translate 2026-06-20 18:27:42 +08:00
Tigah
d72952bf93 fix(linux): clean up leftover session procs and X locks on headless teardown (#15337)
On headless login the desktop manager opens a PAM session, which makes
pam_systemd register a logind session and put the spawned Xorg + window
manager and their children (e.g. pipewire) in a "session-<id>.scope"
cgroup. Teardown only killed the Xorg and wm pids, so the rest of the
session kept running, holding the logind session in "closing" and leaking
runtime sockets and X display numbers on every reconnect.

Capture the session scope cgroup from a child pid and, on teardown, kill the
remaining processes in it and any descendant cgroups (cgroup.procs is not
recursive, and a desktop may move pipewire and apps into child scopes),
excluding our own service process and anything tracked in CHILD_PROCESS
together with its descendants. The connection manager is a sudo child, so the
tracked pid is the wrapper while the real --cm-no-ui worker may be a descendant
(sudo with use_pty runs it under a monitor); both can share the scope when
their PAM stack does not re-home them.

Xorg is killed with SIGKILL, so it also leaves its "/tmp/.X<n>-lock" and
"/tmp/.X11-unix/X<n>" behind; get_avail_display() treats either file as the
display being in use, so the number is never reused and climbs until the
range is exhausted. Remove those files for the session's display on
teardown, as a clean Xorg exit would.

Closes #15183

Signed-off-by: TBX3D <88289044+TBX3D@users.noreply.github.com>
2026-06-20 14:21:42 +08:00
Re*Index. (ot_inc)
a7c55db9ac Fix Japanese text (#15345) 2026-06-20 09:50:04 +08:00
StealUrKill
bff47e2b81 Feature: Add monitor-switch buttons to remote toolbars (#15342)
* Feature: add monitor-switch buttons to remote toolbars

Add buttons to cycle through the remote displays from the toolbars:

- A main-toolbar button and a minimized-handle button, both using a shared SVG icon with the current monitor number overlaid.
- Two opt-in settings under Settings/Other. The minimized-toolbar option is nested under the main-toolbar option.
- The minimized button only appears once the toolbar is collapsed.
- Cycling does not move the remote cursor, matching the existing in-toolbar monitor buttons.

Signed-off-by: StealUrKill <35749471+StealUrKill@users.noreply.github.com>

* fix: respect individual-window display mode when cycling

In "Show displays as individual windows" mode, route the cycle button through openMonitorInNewTabOrWindow like the monitor selector, so each display keeps its own window instead of repurposing the current one.

Signed-off-by: StealUrKill <35749471+StealUrKill@users.noreply.github.com>

---------

Signed-off-by: StealUrKill <35749471+StealUrKill@users.noreply.github.com>
2026-06-20 01:22:20 +08:00
fufesou
3d478c4935 fix(ios): mouse mismatch (#15339)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-19 20:50:56 +08:00
RustDesk
a658e987b7 Revert "Feature: Add monitor-switch buttons to remote toolbars (#15314)" (#15338)
This reverts commit 7c8b0adc1e.
2026-06-19 12:34:59 +08:00
StealUrKill
7c8b0adc1e Feature: Add monitor-switch buttons to remote toolbars (#15314)
* Feature: add monitor-switch buttons to remote toolbars

Add a one-click "switch to next monitor" control to both desktop toolbars:
- Main toolbar: always shown when the remote has more than one monitor,
  styled to match the existing blue icon buttons (white screen, black number).
- Minimized (draggable show/hide) toolbar: off by default, toggled via a new
  "Show monitor switch on minimized toolbar" checkbox in the Display menu and
  persisted as a local option.

Signed-off-by: StealUrKill <35749471+StealUrKill@users.noreply.github.com>

* Update remote_toolbar.dart

* refact: unify monitor-switch button icons, share tooltip

Addressing the review feedback on the monitor-switch toolbar buttons:

- Add assets/display_switcher.svg and use it for both the main and minimized buttons. This replaces the hand-drawn glyph (Containers + magic numbers) on the main toolbar. The icon scales with DPI/theme and the two toolbars stay visually consistent.
- Flip the minimized button's label to white for contrast, since the new icon has a solid screen.
- Move the tooltip string into a shared _MonitorCycle.tooltip getter so both buttons use one source of truth.
- Use const Offstage() for consistency with the surrounding returns.

Signed-off-by: StealUrKill <35749471+StealUrKill@users.noreply.github.com>

* Improve monitor-switch settings and toolbar behavior

- Nest the minimized-toolbar option under the main one in settings only show when the main option is enabled.

- Only show the minimized switch button on the collapsed toolbar handle, so it no longer duplicates the main switch while the toolbar is expanded.

Signed-off-by: StealUrKill <35749471+StealUrKill@users.noreply.github.com>

---------

Signed-off-by: StealUrKill <35749471+StealUrKill@users.noreply.github.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2026-06-19 11:19:08 +08:00
fufesou
a732ebc3e1 fix: win, ci, update RustDeskTempTopMostWindow (#15334)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-19 00:24:48 +08:00
fufesou
30c0867e40 fix(ci): win arm64 (#15333)
* fix(ci): win arm64

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

* fix: ci, less changes

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-19 00:10:37 +08:00
Dennis Ameling
8f50ea64dc Add Windows arm64 support (#15139)
* Add initial arm64 build logic

Signed-off-by: Dennis Ameling <dennis@dennisameling.com>

* Upgrade Flutter to 3.44.0 and introduce Windows arm64 in CI

Signed-off-by: Dennis Ameling <dennis@dennisameling.com>

* Bump bridge build to Flutter 3.44 as well

Signed-off-by: Dennis Ameling <dennis@dennisameling.com>

* Fix install flutter step for Win arm64

* Bump install-llvm-action to v2 for arm64 support

* Fix libsodium logic to only install through vcpkg on win arm64

* Fix Flutter installations on Win

* Flutter XCode: only build the current arch as it defaults to universal

Signed-off-by: Dennis Ameling <dennis@dennisameling.com>

* Ensure that we really have arm64 Dart + Flutter engine in CI

Signed-off-by: Dennis Ameling <dennis@dennisameling.com>

* Enable hwcodec feature now that upstream supports building it

Signed-off-by: Dennis Ameling <dennis@dennisameling.com>

* CI: improve logic for getting Flutter arm64 SDK

Signed-off-by: Dennis Ameling <dennis@dennisameling.com>

* Apply PR feedback (only bump Flutter version on Win arm64)

* Exclude MSI build on arm64

* CI: build the MSI for Windows arm64 (WiX v4 ARM64 platform + native CustomActions)

* Address PR feedback

* Update Cargo.toml

* Update Cargo.lock

* Update Cargo.lock

* Add Flutter 3.44 DialogThemeData background colors

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: Dennis Ameling <dennis@dennisameling.com>
Signed-off-by: 21pages <sunboeasy@gmail.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
Co-authored-by: 21pages <sunboeasy@gmail.com>
2026-06-18 22:37:15 +08:00
fufesou
0797ebb695 Refact/privacy mode 1 multi monitors (#15321)
* 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>

* Fix privacy mode edge cases after multi-monitor overlay changes

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

* Add missing changes

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-18 21:27:44 +08:00
Bia503
c9391fb894 fix(arm64-linux): fix CJK font rendering on flutter-elinux (#15324)
* fix(arm64-linux): fix CJK font rendering on flutter-elinux

The flutter-elinux engine used for ARM64 Linux builds is compiled without
--enable-fontconfig, so Flutter's text shaper cannot discover system fonts.
This causes CJK characters to render as tofu boxes even when fonts such as
Noto Sans CJK are installed. See flutter/flutter#139293.

Fix by loading a CJK font at startup via FontLoader (bypassing fontconfig)
and propagating it through two paths so all text widgets are covered:

1. MyTheme.applyFontFallback() — updates textTheme on both light and dark
   ThemeData so Material components receive the fallback through the theme.

2. _mergeCjkFallback() in GetMaterialApp builders — wraps child widgets in
   DefaultTextStyle.merge so bare Text() widgets and those with inherit:true
   also render CJK characters correctly.

Font discovery queries fc-list for zh, ja, and ko separately, preferring
fonts present in all three sets (true pan-CJK fonts such as NotoSansCJK or
SourceHanSans) over Chinese-only fonts that may lack Japanese kana or Korean
hangul glyphs.  Falls back to a hardcoded search-path list covering
Debian/Ubuntu, Fedora/RHEL, Arch Linux, and WenQuanYi font layouts.

This is an app-level workaround. The engine-level fix is tracked at
flutter/flutter#180235 (open as of 2026-06).

Fixes #10666

Signed-off-by: Bia503 <yinwenche189@gmail.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Signed-off-by: Bia503 <yinwenche189@gmail.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-18 20:47:24 +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
rustdesk
bf206dc309 fixing https://github.com/rustdesk/rustdesk/issues/15293 2026-06-16 11:36:53 +08:00
fufesou
6d116cf1c9 fix(clipboard): Windows DIB images, fill missing alpha (#15296)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-16 11:29:53 +08:00
RustDesk
1fc33218dc Revert "fix(iPad): keep touch gestures with external mouse (#14652)" (#15288)
This reverts commit 5b7ad339b8.
2026-06-15 15:13:54 +08:00
21pages
b73e5bbfa0 opt: release clipboard config lock before updates (#15277)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-06-14 17:27:19 +08:00
fufesou
78533e428e feat: theme logo (#15268)
* feat: theme logo

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

* perf(flutter): cache theme logo asset resolution

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-14 13:47:39 +08:00
fufesou
cc7fe4efdc Fix/generate py target injection (#15248)
* fix: generate.py, target injection

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

* refact: logs

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

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Update port_forward.rs

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-11 23:09:34 +08:00
littlestejan
84af60c07e Fix clipboard synchronization not fully disabled in View Only mode (#15224)
* fix: view-only clipboard sync

Signed-off-by: Setani <little_stejan@hotmail.com>

* fix: gate Android MultiClipboards handling with clipboard permissions

Signed-off-by: Setani <little_stejan@hotmail.com>

---------

Signed-off-by: Setani <little_stejan@hotmail.com>
2026-06-10 07:42:58 +08:00
fufesou
6426269d41 Refact/printer driver default unchecked (#15191)
* refact: installation, printer driver, default unchecked

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

* refact: silent install, get option from the reg values

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

* refact: silent install, arg printer=[0|1]

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-06 08:51:08 +08:00
dependabot[bot]
7c41f993fe Git submodule: Bump libs/hbb_common from df6badc to 387603f (#15189)
Bumps [libs/hbb_common](https://github.com/rustdesk/hbb_common) from `df6badc` to `387603f`.
- [Release notes](https://github.com/rustdesk/hbb_common/releases)
- [Commits](df6badca5b...387603f47c)

---
updated-dependencies:
- dependency-name: libs/hbb_common
  dependency-version: 387603f47cbb15c0d3dc3d67ae3396d3eb707daf
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-04 14:04:02 +08:00
rustdesk
0c86d46162 translate all 2026-06-02 23:33:40 +08:00
bovirus
e87797418f Update it.rs (#15173) 2026-06-02 23:32:04 +08:00
Lynilia
78a3a2aeb9 Update fr.rs (#15172) 2026-06-02 22:26:19 +08:00
bovirus
e18cf7a245 Update it.rs (#15171) 2026-06-02 22:23:06 +08:00
rustdesk
50d5823ef5 1.4.7 2026-06-02 17:06:23 +08:00
fufesou
518296f257 fix: bytes codec, reserver(), check max (#15168)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-02 16:39:50 +08:00
fufesou
3217125dd3 fix(keyboard): wayland clipboard input prompt (#14700)
* fix(keyboard): wayland clipboard input prompt

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

* fix(wayland): Simple refactor

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

* fix(wayland): clipboard input, remove unused code

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

* fix(wayland): Simple refactor

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

* fix(wayland): dialog, better enableAndContinue

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

* fix(wayland): input dialog consent

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

* fix(wayland): prompt text

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

* fix(wayland): text input

1. Use `keysym` for the installed version if possible.
2. Use the clipboard if the string cannot be fully handled by `keysym`.

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

* fix(wayland): input prompt dialog

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

* fix(wayland): translations

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

* fix(wayland): dialog, title type

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

* fix(wayland): better decode_utf8_prefix()

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

* fix(wayland): better process_chr()

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

* fix(wayland): unit tests

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

* fix(wayland): input prompt dialog, no icon

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

* fix(wayland): input dialog, Toast show the result

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

* fix(wayland): input dialog, showToast() on persist failed

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

* fix(wayland): input prompt, better dialog

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

* fix(wayland): input prompt dialog, translations

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

* fix(input): better wayland clipboard input prompt

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

* fix(input): wayland clipboard, link external app

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

* fix(input): trivial changes

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

* fix(input): wayland clipboard input, dialog content

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

* fix(input): tranlsations

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

* fix(input): translations

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

* fix(input): translations

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

* fix(input): translations

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-02 16:06:35 +08:00
bovirus
00032854eb Update it.rs (#15167)
* Update it.rs

* Update it.rs
2026-06-02 16:00:43 +08:00
21pages
d99ddf6816 Add Android device deployment flow (#15146)
* Add Android device deployment flow

  Notify the Android Flutter UI when the server requires deployment, add a deploy dialog with API token/custom ID inputs, and reuse shared deploy logic
  for CLI and FFI

Signed-off-by: 21pages <sunboeasy@gmail.com>

* Hide Android deploy API token input

Signed-off-by: 21pages <sunboeasy@gmail.com>

* add more translations

Signed-off-by: 21pages <sunboeasy@gmail.com>

* optimize transations

Signed-off-by: 21pages <sunboeasy@gmail.com>

* Hide deploy action for outgoing-only clients

Signed-off-by: 21pages <sunboeasy@gmail.com>

* Fix deployment register throttle state reset

Signed-off-by: 21pages <sunboeasy@gmail.com>

* Move Android deploy dialog out of settings page

Signed-off-by: 21pages <sunboeasy@gmail.com>

* Use async mutex for deploy register throttle

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-06-02 14:28:30 +08:00
RustDesk
32c6e32e04 Revert "Revert "fix: add integer overflow check in wf_cliprdr.c (#15142)" (#1…" (#15166)
This reverts commit c55b1f3359.
2026-06-02 11:45:24 +08:00
RustDesk
c55b1f3359 Revert "fix: add integer overflow check in wf_cliprdr.c (#15142)" (#15160)
This reverts commit fabeae4180.
2026-06-01 16:26:20 +08:00
OrbisAI Security
fabeae4180 fix: add integer overflow check in wf_cliprdr.c (#15142)
* fix: V-003 security vulnerability

Automated security fix generated by OrbisAI Security

Signed-off-by: orbisai0security <mediratta01.pally@gmail.com>

* fix: add integer overflow check in wf_cliprdr.c

At line 774, memory is allocated using calloc with instance->m_nStreams as the count parameter

Signed-off-by: orbisai0security <mediratta01.pally@gmail.com>

* Apply code changes: @orbisai0security can you address code review comm...

* fix(cliprdr): ci

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

* fix(cliprdr): ci, use msvc

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

* fix(cliprdr): ci

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

* fix(cliprdr): ci, test

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

* fix(cliprdr): fix ci

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

* fix(cliprdr): fix ci

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

* fix(cliprdr): fix ci

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

* fix(cliprdr): ci

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

* Apply code changes: @orbisai0security can you address code review comm...

* adding bounds check and tests

* Apply code changes: @orbisai0security can you address code review comm...

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Signed-off-by: orbisai0security <mediratta01.pally@gmail.com>
Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: fufesou <linlong1266@gmail.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-01 15:26:39 +08:00
fufesou
5eed50961d fix(crypt): symmetric crypt, zero nonce (#15144)
* fix(crypt): symmetric crypt, zero nonce

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

* update hbb_common

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-01 12:01:26 +08:00
Maison da Silva
bed0976eb9 Fix Portuguese translations in ptbr.rs (#15149)
Corrected Portuguese translations for consistency and clarity.
2026-06-01 10:38:31 +08:00
VenusGirl❤
70d92d9b07 Update Korean README with improved formatting (#15153) 2026-06-01 10:38:04 +08:00
Maison da Silva
fb4ba31504 Revise README-PTBR for clarity and updates (#15152)
Updated various sections of the README in Portuguese, including links, instructions, and descriptions for clarity and consistency.
2026-06-01 10:37:32 +08:00
Muad'Dib
152c5c71b1 fix(android): close session on dispose to prevent reconnect wedge (#15143)
RemotePage.dispose() only reaches sessionClose at the tail of gFFI.close(),
behind several awaits (canvas save, image update, the enable_soft_keyboard
platform call). If the app is backgrounded while the page is disposing,
dispose can be suspended before that runs, so the session is never torn down.
The next reconnect re-attaches to the leaked session (mobile reuses a constant
sessionId) and is stuck on "Connecting..." forever while the orphaned io_loop
keeps streaming.

Dispatch sessionClose at the start of dispose so teardown happens synchronously
on route pop, before backgrounding can interrupt it. The sessionClose in
gFFI.close() becomes a no-op once the session is already removed.

Fixes #15060

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 10:24:53 +08:00
Maison da Silva
fa369365a5 Update Portuguese translations for clarity (#15135)
* Update Portuguese translations for clarity

Update Portuguese translations for clarity

* Update ptbr.rs

* Update Portuguese translations for clarity

* Update Portuguese translation for version warning

* Refine Portuguese translations in ptbr.rs

Updated translations for user input blocking and OS password.

* Fix translation for 'Take screenshot' in Portuguese

* Change translation for 'Note' to 'Anotações'

* Update translation from 'nota' to 'anotação'
2026-05-30 15:44:04 +08:00
hatterp
7345366ba7 Add Polish translations for privacy mode and toolbar docking (#15134) 2026-05-29 17:52:42 +08:00
Kleofass
6151ea7128 Update lv.rs (#15133) 2026-05-29 14:09:43 +08:00
Alex Rijckaert
440ab26b69 Update Dutch translations (#15132) 2026-05-29 08:49:27 +08:00
21pages
caadd72ab2 Add advanced option to allow CLI settings when custom client toggles Disable settings (#15138) 2026-05-28 17:52:55 +08:00
Mr-Update
d59d543ec1 Update de.rs (#15131) 2026-05-28 14:56:19 +08:00
bilimiyorum
58d1109510 Update tr.rs (#15119)
New string entry
2026-05-28 14:52:41 +08:00
bovirus
9c52e25a6a Update Italian language (#15118) 2026-05-28 13:42:14 +08:00
solokot
62a44c5a09 Update ru.rs (#15117) 2026-05-28 13:41:48 +08:00
MichaIng
e5fa40e903 fix(packaging): add support for time64 packages (#14465)
Debian 13 Trixie and Ubuntu 24.04 Noble come with time64 transitioned packages: https://wiki.debian.org/ReleaseGoals/64bit-time
This means, all packages with use the time_t syscall on 32-bit do now use the time64 syscall instead, to get 64-bit year 2038 prove UNIX time values. Those packages get a "t64" suffix for their name, also for 64-bit architectures for consistency. Since time_t values on 64-bit are 64-bit already, no actual change happened there, and a package dependency without the t64 suffix is still satisfied by the packages with t64 suffix, via "Provides" attribute. This however is not he case for 32-bit.

The rustdesk package currently depends on libgtk-3-0 and libasound2, while Debian Trixie and Ubuntu Noble serve libgtk-3-0t64 and libasound2t64. On 64-bit architectures (amd64 and arm64), the available packages satisfy the dependency, but on 32-bit (armhf) this is not the case. In turn the rustdesk armv7-sciter.deb package cannot be installed on recent distro versions.

This commit solves the issue by adding the respective t64 packages are alternative dependency. If available, the t64 package is installed, else (on older distro versions), the one without t64 suffix.

Signed-off-by: MichaIng <micha@dietpi.com>
2026-05-27 15:05:37 +08:00
VenusGirl❤
8177083992 Update Korean (#15113) 2026-05-27 14:10:39 +08:00
Maison da Silva
4bfd8e9f61 Fix Portuguese translations for consistency (#15112)
* Fix Portuguese translations for consistency

Fix Portuguese translations for consistency

* Update translation for screenshot action tip

* Fix capitalization in Portuguese translations

* Fix translation for remote session display usage

* Translate allow-remote-toolbar-docking-any-edge message
2026-05-27 14:10:17 +08:00
rustdesk
81e7d27ec8 pin more action 2026-05-26 19:03:03 +08:00
rustdesk
f3fc0b5ac2 pin unpinned action 2026-05-26 18:08:28 +08:00
rustdesk
fb7bca436b fix ci 2026-05-26 17:08:32 +08:00
rustdesk
c19a0ceba2 more "cargo build --locked" 2026-05-26 11:45:15 +08:00
fufesou
1f26e452fc refact(password): encrypt (#15073)
* refact(password): encrypt

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

* refact(password): simplify preset password

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

* update hbb_common

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

* refact(password): clear password, do not clear salt

* refact(password): update hbb_common

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

* refact(password): merge import

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-05-26 11:11:25 +08:00
Lynilia
0af6b7ede9 Update fr.rs (#15111) 2026-05-25 16:01:34 +08:00
Luke
6ad56075d6 Drag whole toolbar; snap to all four edges of the remote session window (#15051)
* Drag whole toolbar; snap to all four edges

Today the drag handle on the remote-session toolbar repositions only
the handle row -- the icons themselves stay centered at the top. This
change applies the position to the entire toolbar wrapper so dragging
the handle moves the whole thing, and extends snapping from top-only
to any of the four window edges.

When docked left/right the toolbar reflows vertically. A live ghost
preview shows where the toolbar will land while you drag, with a small
hysteresis bias to keep the preview from flickering near corners.

The legacy 'remote-menubar-drag-x' session option is read as a fallback
on first load so existing users keep their saved horizontal position;
new option keys are 'remote-menubar-edge' and 'remote-menubar-frac'.

Tested locally on Windows. macOS / Linux / web desktop use the same
shared widget with no platform-specific calls, but I did not verify
them.

* Load edge independently and clamp loaded fraction

Addresses CodeRabbit review on #15051: parse the saved edge regardless
of whether the new fraction option is present so a partial write of
frac doesn't reset the toolbar back to top, and clamp the loaded
fraction to the kOptionRemoteMenubarDragLeft/Right contract so a
corrupted or out-of-range saved value can't bypass the bounds until
the user drags again.

* Require edge activation zone to switch dock; preserve horizontal slide

Per review feedback on #15051: nearest-edge-wins made a low-intent
horizontal slide too easy to escalate into a high-impact orientation
change (vertical reflow on left/right dock). The default drag now
keeps the toolbar on its current dock edge and just updates the
fraction along that edge -- the prior horizontal-slide behavior.

An alternate edge is only previewed/committed when the cursor enters
its 32 px activation zone; once previewed, the cursor has to move
back 64 px before reverting (hysteresis at the zone boundary).

* Gate multi-edge docking behind a settings toggle; default = horizontal slide

Replaces the activation-zone approach with an explicit opt-in setting
in Settings -> Other ("Allow docking remote toolbar to any window
edge"). This addresses the concern that a low-intent horizontal drag
shouldn't be able to trigger a high-impact orientation change, while
still letting users who want multi-edge docking opt in cleanly.

Default (toggle off):
  - The original horizontal slide is preserved.
  - The bug fix from the first commit still applies: dragging the
    handle moves the whole toolbar, and the position persists across
    collapse/expand (no more re-center on re-open).
  - Draggable is axis-locked to horizontal so the feedback widget
    stays on the top line during drag.

Opt-in (toggle on):
  - Full nearest-edge wins with the live preview ghost and corner
    hysteresis; toolbar reflows vertically on left/right docks.
  - Draggable is unlocked for 2D drag.

Reads the option via mainGetLocalBoolOptionSync so the toolbar's
default state matches what the settings checkbox shows; the option
key uses the allow- prefix so unset defaults to off.

Takes effect on next session (setting is read at session init).

The setting key (allow-multi-edge-toolbar-dock) is read by the
existing local-options machinery and persists per-install without
needing to be registered in libs/hbb_common's KEYS_LOCAL_SETTINGS.
Can add that registration in a parallel hbb_common PR if preferred.

* Fix remote toolbar drag positioning & persistence

Align drag fraction calculation with the toolbar's actual travel range,
keep preview sizing stable during drag, and preserve legacy horizontal
position storage when multi-edge docking is disabled.

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

* Remote toolbar snap edges

1. Translations
2. Apply option to remote windows on changed

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

* fix: avoid remote toolbar docking jumps on setting reload

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

* Fix remote toolbar docking updates and drag sync

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

* refact: translation key

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

* feat(toolbar-snap-edges): test web

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

* Fix remote toolbar docking sync and vertical layout

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

* Fix remote toolbar monitor controls on side docks

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: fufesou <linlong1266@gmail.com>
2026-05-24 19:08:45 +08:00
Maison da Silva
b81ae6c894 Translate various labels to Portuguese-BR (#15086)
Update
2026-05-22 18:36:15 +08:00
dependabot[bot]
546e9f1702 Git submodule: Bump libs/hbb_common from c8cbb6b to 9043c15 (#15067)
Bumps [libs/hbb_common](https://github.com/rustdesk/hbb_common) from `c8cbb6b` to `9043c15`.
- [Release notes](https://github.com/rustdesk/hbb_common/releases)
- [Commits](c8cbb6be28...9043c15acc)

---
updated-dependencies:
- dependency-name: libs/hbb_common
  dependency-version: 9043c15acc6d5b42b6c12ad284c16c1ec172f1f0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-21 09:07:43 +08:00
fufesou
bb51c6aa42 fix(ipc): cmdline, unit tests (#15069)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-05-18 17:03:04 +08:00
fufesou
78e8134ad5 fix(ipc): cmdline, use scope, deploy (#15068)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-05-18 16:52:22 +08:00
fufesou
bc2c36215d fix(ipc): scope active-user IPC routing to root CLI main requests (#15058)
* fix(ipc): scope active-user IPC routing to root CLI main requests

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

* fix(ipc): cmdline, comments fails close

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

* fix(ipc): cmdline, better check

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

* fix(ipc): cmdline, try active uid when no --server processes

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

* fix(ipc): cmdline, select active uid

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

* fix(ipc): remove unused import

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-05-18 16:32:46 +08:00
IronCodeStudios
377547fa11 scrap/wayland: insert videoconvert to fix screencast on COSMIC / DMA-BUF portals (#15063)
On Wayland compositors whose xdg-desktop-portal backend exposes screencast
frames as DMA-BUF buffers — notably xdg-desktop-portal-cosmic 0.1.0 on
Pop!_OS 24.04 / COSMIC — inbound screen capture fails. PipeWireRecorder
links pipewiresrc directly to an appsink whose caps only accept
video/x-raw BGRx/RGBx in system memory. That format set is too narrow for
the portal's buffer-type / modifier negotiation, which collapses with:

  pw.link: negotiating -> error no more output formats (-22)
  gstpipewiresrc: stream error: no more output formats
  gstbasesrc: streaming stopped, reason not-negotiated (-4)
  ERROR src/server/wayland.rs: Failed scrap Element failed to change its state

Inserting a videoconvert element between pipewiresrc and appsink widens
the negotiable format set to any system-memory video/x-raw format, giving
the portal room to settle on a format it can deliver via its SHM path.
videoconvert then converts to the BGRx/RGBx the appsink expects.

Verified on Pop!_OS 24.04 / COSMIC with gst-launch, before and after:

  # fails (current behaviour):
  gst-launch-1.0 pipewiresrc path=N ! video/x-raw,format=BGRx ! fakesink
  # works (with this change):
  gst-launch-1.0 pipewiresrc path=N ! videoconvert ! video/x-raw,format=BGRx ! fakesink

After the change, inbound connections capture and stream the desktop
normally and the "Failed scrap" error no longer occurs.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 16:02:23 +08:00
RustDesk
472c4fc03a --deploy, reuse the device token (#15035)
* --deploy, reuse the device token

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix review

* no id validation in deploy, so to keep the same behavior in udp register
pk

* Fix collapsed toolbar drag preview sizing

* Revert "Fix collapsed toolbar drag preview sizing"

This reverts commit 66e39abb74.

* remove too many logs

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-16 14:41:34 +08:00
rustdesk
9f8f726f12 fix compile 2026-05-15 17:30:59 +08:00
flusheDData
701a9c6cdc New terms added (#15036)
* Update es.rs

New terms added

* Update es.rs

New terms added

* Update Spanish translations for various strings

* Fix typo in Spanish translation for TLS fallback

* Add Spanish translations for various UI elements

* Update es.rs

---------

Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2026-05-15 15:31:25 +08:00
Alex Rijckaert
0d40cf2101 Update Dutch translations (#15024)
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2026-05-14 16:43:40 +08:00
rustdesk
dd265dadd7 update hbb_common 2026-05-13 18:08:08 +08:00
Alex Rijckaert
fe5a8cb2ad Update Dutch translation (#14984) 2026-05-13 14:59:48 +08:00
John Fowler
b6caa1a7b2 hu.rs update (#14983)
Translate a new string.
2026-05-13 14:59:29 +08:00
fufesou
55c9707639 fix(msi): check install folder, remove files when uninstall (#15011)
* fix(msi): check install folder, remove files when uninstall

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

* fix(msi): harden install folder normalization cleanup

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

* fix(msi): better file attributes

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

* fix(mis): Simple refactor

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

* fix(msi): avoid path-based attribute changes in cleanup

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

* fix(msi): custom action, unset flag read before del

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-05-12 16:24:50 +08:00
Yan Wang
d8808baa83 Allow macOS monitor switching in privacy mode (#15004)
Co-authored-by: Codex <codex@openai.local>
2026-05-11 12:58:49 +08:00
fufesou
1978020d27 fix(custom-client): desktop, incoming only, touch drag (#14928)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-05-11 12:58:32 +08:00
fufesou
0e4b91b8d7 Harden os password (terminal windows and headless linux) anti brute force (#14985)
* fix(windows): terminal, preauth bruteforce

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

* fix(linux): headless, preauth bruteforce

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

* fix(linux): headless, OS login, minimal fix

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

* Terminal session, click-only

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

* Simple refactor, logs

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

* harden os password, better scoped failure set

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

* harden os password, ip failure count

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

* Check prelogin before starting cm

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

* Isolate terminal OS login failure tracking

Terminal OS login no longer reads or updates the default RustDesk
per-IP failure bucket. It now uses only the OS credential policy, while
RustDesk password attempts keep using the existing LOGIN_FAILURES[0]
bucket.

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-05-11 12:58:01 +08:00
fufesou
9c831dc59b fix(fs): file transfer, reconnect, restore dir (#14925)
* fix(fs): file transfer, reconnect, restore dir

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

* fix(fs): simple refactor

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

* fix(fs): simple refactor

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-05-10 10:08:29 +08:00
fufesou
b757e97c11 fix(translation): ja (#14993)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-05-10 10:02:42 +08:00
fufesou
9df486a689 fix(ipc): harden local IPC authorization and portable-service bootstrap flow (#14671)
* fix(ipc): harden ipc access

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

* fix(ipc): full cmd path, comments, simple refactor

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

* fix(ipc): portable service, ipc exit

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

* fix(ipc): Remove unused logs

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

* fix(ipc): Use SetEntriesInAclW instead of icacls

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

* fix(ipc): Comments

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

* fix(ipc): check is_reparse_point

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

* fix(ipc): shmem name, no fallback

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

* fix(ipc): Simple refactor

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

* fix(ipc): better exit and clear

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

* fix(ipc): portable service, better exit

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

* fix(ipc): comments, id -u

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

* fix: comments linux headless, rx desktop ready

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

* fix(ipc): magic number

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

* fix(ipc): update deps

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

* Update Cargo.lock

* Update Cargo.lock

* fix(ipc): harden ipc, test `identity_unavailable`

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

* fix(ipc): portable service, check dir of shmem

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

* fix(ipc): macos, better check exe allowed

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

* fix(ipc): update hbb_common

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

* fix(ipc): update hbb_common

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

* fix(ipc): harden ipc, better active uid for uinput

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

* fix(ipc): harden portable service token validation

Compare portable service IPC tokens in constant time and document the
CSPRNG source used for one-time token generation. Clarify Windows IPC
authorization comments around canonical path matching and partial peer
identity lookup.

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

* fix(ipc): simple refactor

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

* fix(ipc): harden portable service token handling

Generate the portable service IPC token directly from OsRng, keep token
comparison in the IPC layer as a fixed-length byte-wise check, and document
the malformed-frame behavior for protected service IPC.

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

* fix(ipc): comments

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2026-05-09 18:15:00 +08:00
VenusGirl❤
72d27c3c47 Update Korean (#14956) 2026-05-08 17:49:17 +08:00
RustDesk
6c20fc936d Terminal utf8 and reconnect (#14895)
* fix: handle incomplete UTF-8 sequences in terminal output, rework on https://github.com/rustdesk/rustdesk/pull/14736

* Fix terminal auto-reconnect freeze:  reconnect resumes terminal output, while multi-tab reconnect avoids restoring duplicate tabs for terminals that are already open.

* fix(terminal): subtract with overflow

```
thread '<unnamed>' panicked at src\server\terminal_service.rs:476:17:
attempt to subtract with overflow
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'tokio-runtime-worker' panicked at src\server\terminal_service.rs:1576:50:
called `Result::unwrap()` on an `Err` value: PoisonError { .. }
[2026-04-25T07:17:34Z ERROR librustdesk::server::service] Failed to join thread for service ts_9badd3fe-2411-4996-9f40-93c979009edd, Any { .. }
```

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

* fix ios enter: https://github.com/rustdesk/rustdesk/issues/14907

* fix(terminal): reconnect, error handling

1. Terminal shows "^[[1;1R^[[2;2R^[[>0;0;0c"
2. NaN

```
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Converting object to an encodable object failed: NaN
...
```

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

* fix(terminal): dialog, close window

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

* fix(terminal): close terminal window on disconnect dialog

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

* fix(terminal): merge reconnect backlog into replay output

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

* fix(terminal): avoid reconnect stalls and delayed layout writes

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

* fix(terminal): remove invalid test

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

* fix(terminal): schedule frame before flushing buffered output

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

* fix(terminal): windows&macos, charset utf-8

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

* fix(terminal): reconnect suppress next output

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

* fix: cap terminal reconnect replay output

  - split reconnect replay backlog into capped chunks
  - mark terminal data replay chunks for client-side suppression
  - avoid using open-message text to suppress xterm replies
  - reuse default terminal padding value
  - remove misleading Enter-key normalization PR link

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

* fix(terminal): env en_US.UTF-8

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

* fix(terminal): reconnect, refactor

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

* fix(terminal): flag, retry output

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

* fix(terminal): update hbb_common

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

* fix(terminal): comments

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

* fix(terminal): comments utf-8 chunk accumulator

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

* fix(terminal): update hbb_common

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: fufesou <linlong1266@gmail.com>
2026-05-07 13:27:13 +08:00
21pages
5439ec38b6 Revert "fix web break introduced in 38f130071 fix(linux): enable mouse side buttons in remote sessions (#14848)" (#14973)
This reverts commit d5d0b01266.
2026-05-06 20:20:17 +08:00
rustdesk
8b8a64f870 revert hbb_common to old one 2026-05-06 19:40:52 +08:00
rustdesk
92509f8e8a update hbb_common 2026-05-06 19:35:47 +08:00
Lynilia
0221634a4d Update fr.rs (#14955) 2026-05-06 19:32:59 +08:00
Mr-Update
9d1f86fbc6 Update de.rs (#14953) 2026-05-06 19:32:41 +08:00
rustdesk
f29dec7b13 harden switch side 2026-05-06 19:27:56 +08:00
rustdesk
d5d0b01266 fix web break introduced in 38f130071 fix(linux): enable mouse side buttons in remote sessions (#14848) 2026-05-06 18:27:34 +08:00
bovirus
5abae617dc Italian language update (#14949) 2026-05-04 16:50:42 +08:00
bilimiyorum
52d62da002 Update tr.rs (#14948)
1- New string entry
2- A minor improvement for terminological consistency
2026-05-04 16:50:23 +08:00
solokot
253d632709 Update ru.rs (#14947) 2026-05-04 16:49:49 +08:00
fufesou
383a5c3478 feat: option, enable-privacy-mode & enable-perm-change-in-accept-window (#14875)
* feat: option, privacy mode

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

* feat(privacy mode): update libs/hbb_common

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

* feat(privacy mode): turn off on disable privacy mode

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

* feat(privacy mode): better check if supported

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

* feat(option): enable perm change in accept window

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-05-02 00:44:22 +08:00
orbisai0security
d4a1430c27 fix: V-002 security vulnerability (#14924)
Automated security fix generated by Orbis Security AI
2026-04-29 13:15:21 +08:00
KaneBarns
bfd31d21e4 Update build.py (#11341) 2026-04-28 15:08:10 +08:00
Amirhosein Akhlaghpoor
590296b297 fix: iPad mouse down detection for physical mouse input (#14515)
* fix: iPad mouse down detection

Signed-off-by: Amirhossein Akhlaghpour <m9.akhlaghpoor@gmail.com>

* fix(ipad): remove redundant check

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

* fix(ipad): Simple refactor

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

---------

Signed-off-by: Amirhossein Akhlaghpour <m9.akhlaghpoor@gmail.com>
Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: fufesou <linlong1266@gmail.com>
2026-04-28 15:03:41 +08:00
eason
ee8cc0c06b fix(linux): prevent X11 BadWindow crash in get_focused_display (#14561)
* fix(linux): prevent X11 BadWindow crash in get_focused_display

When the active window is destroyed between xdo_get_active_window and
xdo_get_window_location/xdo_get_window_size calls, the default X11
error handler terminates the process with a BadWindow error. This
causes the rustdesk --server process to crash and the remote session
to disconnect and reconnect every time the user closes a window.

Install a custom X error handler around the xdo calls that catches
BadWindow errors and returns gracefully instead of crashing.

Fixes: https://github.com/rustdesk/rustdesk/issues/9003

Co-Authored-By: Claude (claude-opus-4-6) <noreply@anthropic.com>
Signed-off-by: easonysliu <easonysliu@tencent.com>

* fix(linux): prevent BadWindow crash in focus display lookup

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

---------

Signed-off-by: easonysliu <easonysliu@tencent.com>
Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: easonysliu <easonysliu@tencent.com>
Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
Co-authored-by: fufesou <linlong1266@gmail.com>
2026-04-28 11:04:29 +08:00
s1korrrr
99b565ef40 fix(iOS): preserve local pasteboard sync from Windows hosts (#14659)
* fix(ios): accept windows clipboard updates locally

Signed-off-by: Rafal <mrsikorarafal@gmail.com>

* docs: document clipboard text helpers

* fix(iOS): sync clipboard, debug

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

---------

Signed-off-by: Rafal <mrsikorarafal@gmail.com>
Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: fufesou <linlong1266@gmail.com>
2026-04-28 10:55:28 +08:00
fufesou
1e6a3dc644 fix(android): waiting for image, one cause (#14919)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-04-27 22:37:22 +08:00
s1korrrr
5b7ad339b8 fix(iPad): keep touch gestures with external mouse (#14652)
* fix(ipad): keep touch gestures with external mouse

Signed-off-by: Rafal <mrsikorarafal@gmail.com>

* fix(mobile): touch gesture on physical mouse connected

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

* fix(ipad): revert 9ee100b53e

keep touch gestures with external mouse

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

* fix(mobile): align view camera page with remote page

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

---------

Signed-off-by: Rafal <mrsikorarafal@gmail.com>
Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: fufesou <linlong1266@gmail.com>
2026-04-27 19:44:35 +08:00
Sergiusz Michalik
7308c448f1 fix(client): serialize X11 keyboard grab and debounce focus feedback (#14836)
* fix(client): serialize X11 keyboard grab and debounce focus feedback

When two RustDesk sessions run fullscreen on separate monitors on
Linux/X11, keyboard input gets stuck on the wrong session or stops
working entirely. This happens because each Flutter isolate calls
change_grab_status concurrently, racing on KEYBOARD_HOOKED and the
rdev grab channel.

Additionally, XGrabKeyboard causes a focus-change feedback loop:
grab shifts focus away from the Flutter window, triggering PointerExit,
which releases the grab, restoring focus, triggering PointerEnter,
which re-grabs -- cycling at ~10 Hz and blocking keyboard input.

Fix by:
- Serializing grab transitions with a mutex and tracking the owning
  session (by lc.session_id), so a stale Wait from session A cannot
  clobber session B's freshly acquired grab.
- Debouncing Wait events (300 ms) from the same session that just
  acquired the grab, breaking the X11 focus feedback loop.
- Refreshing the debounce timer on idempotent Run calls (enterView
  while already owner), keeping the grab stable during normal use.

Signed-off-by: Sergiusz Michalik <github@latens.me>

* fix(client): add deferred release and dedup for debounced Wait

When a Wait is debounced (within 300ms of grab acquisition), schedule
a deferred release thread that re-checks after the debounce window.
If no new Run refreshed the grab, the deferred thread releases it,
ensuring a genuine leave within the debounce window is not lost.

Add a deferred_pending flag to GrabOwnerState to prevent spawning
redundant threads during the X11 focus feedback loop.

Signed-off-by: Sergiusz Michalik <github@latens.me>

* fix(client): use window-scoped ID and fix deferred-release re-arming

Address PR review feedback:
- Use per-window UUID instead of connection-scoped lc.session_id so two
  windows viewing the same peer get distinct grab owners
- Reset deferred_pending on both idempotent Run refresh and owner
  handoff, so a subsequent Wait can always spawn a fresh timer
- Replace manual Default impl with derive

* fix(client): recover from poisoned mutex instead of panicking

* docs: clarify cross-platform rationale for GrabOwnerState

* fix(client): only clear deferred_pending when timer snapshot matches

* fix(client): use full u128 window ID, downgrade grab logs to debug

- Widen GrabOwnerState.owner to u128 to avoid theoretical collision
  from truncating a 128-bit UUID to 64 bits
- Downgrade all grab transition log::info! to log::debug! to reduce
  log noise during routine window switches
- Clear deferred_pending on post-debounce release path to maintain
  the "deferred_pending => timer in flight" invariant

* fix(client): gate GRAB_DEBOUNCE_MS with cfg(target_os = "linux")

* fix(grab): release grabbed keys without clobbering new owner state

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

* fix(keyboard): Simple refactor

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

---------

Signed-off-by: Sergiusz Michalik <github@latens.me>
Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: fufesou <linlong1266@gmail.com>
2026-04-26 22:46:41 +08:00
Amirhosein Akhlaghpoor
c8ba99d1a1 flutter: shift after one shot IME capitalization (#14695)
* flutter: shift after one shot IME capitalization

Signed-off-by: Amirhossein Akhlaghpour <m9.akhlaghpoor@gmail.com>

* flutter: clarify stale mobile shift handling

Signed-off-by: Amirhossein Akhlaghpour <m9.akhlaghpoor@gmail.com>

* fix(android): gboard shift stuck

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

* fix(android): gboard shift stuck, remove unused param

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

* fix(android): gboard shift stuck, release shift before sending events

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

* chore(flutter): document stale mobile shift release flow

Signed-off-by: Amirhossein Akhlaghpour <m9.akhlaghpoor@gmail.com>

---------

Signed-off-by: Amirhossein Akhlaghpour <m9.akhlaghpoor@gmail.com>
Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: fufesou <linlong1266@gmail.com>
2026-04-26 22:44:26 +08:00
Azhar
5ea6714db8 Fix: replace unwrap() with proper error handling in CLI password prompt (#14910)
Signed-off-by: bunnysayzz <stfuazzo@gmail.com>
2026-04-26 21:28:05 +08:00
fufesou
3a1622e8b5 refact(AGENTS.md): code rules, tokio (#14911)
* refact(AGENTS.md): code rules, tokio

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

* Update AGENTS.md

* Update AGENTS.md

* Update AGENTS.md

* Update AGENTS.md

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2026-04-26 21:25:31 +08:00
Sergiusz Michalik
38f1300717 fix(linux): enable mouse side buttons in remote sessions (#14848)
* fix(linux): enable mouse side buttons in remote sessions

Flutter's Linux embedder never delivers X11 button 8/9 (back/forward)
events to Dart, so mouse side buttons were silently dropped in remote
sessions.

Intercept these buttons at the GDK level via button-press/release-event
handlers on all windows (main + sub-windows) and forward them through
a dedicated platform channel to the active InputModel session.

Also add a defensive XSetPointerMapping call during enigo init to
extend the X11 core pointer button map to 9 buttons on servers where
it is smaller (e.g. minimal X server configurations).

* fix: address review feedback for side button support

- Use XOpenDisplay/XCloseDisplay instead of reading Display* from
  xdo_t's private struct layout at offset 0 (fragile ABI assumption)
- Track side button down ownership per button via a Map instead of a
  single slot, preventing cross-button mismatch on overlapping presses

* fix: gate side buttons on view-only and fix teardown

- Skip side button events in view-only sessions (consistent with
  other mouse entry points)
- Release held side buttons on session close to avoid stuck buttons
  on the remote
- Drop unpaired 'up' events instead of falling back to the active
  model, which could send to the wrong session

* docs: add clarifying comments from review feedback

- Note global scope of XSetPointerMapping and that it runs once
  via lazy_static singleton
- Clarify sub-window callback is safe on X11-only builds
- Document per-isolate design of initSideButtonChannel

* fix: replace broken XSetPointerMapping with diagnostic check

XSetPointerMapping requires the length to match XGetPointerMapping's
return value - it cannot extend the button count. The previous code
would trigger a BadValue X error on servers with fewer than 9 buttons.

Replace with a diagnostic-only check that logs whether the core
pointer has enough buttons for side button simulation. RustDesk's
uinput "Mouse passthrough" device already provides the needed buttons
in practice.

Also add .catchError to fire-and-forget side button releases during
session teardown to prevent unhandled async errors.

* fix: ensure side button releases bypass permission checks

If permissions change between button down and up (e.g. keyboardPerm
revoked, view-only toggled), sendMouse's early return would suppress
the release, leaving a stuck button on the remote.

Add _sendMouseUnchecked that bypasses permission checks, used for:
- Side button 'up' events (matching a recorded 'down')
- Forced releases during session teardown

Gate all permission checks (isViewOnly, keyboardPerm, isViewCamera)
at the 'down' entry point before recording in _sideButtonDownModels.

* fix: add NULL guards and avoid blocking platform channel handler

- Add NULL checks for FL_VIEW cast and channel creation in
  on_subwindow_created (review feedback from fufesou)
- Use fire-and-forget (unawaited) for _sendMouseUnchecked calls
  inside the platform channel handler to avoid blocking platform
  messages when sessionSendMouse is slow (review feedback from Copilot)

* fix: remove circular import and skip X11 check on Wayland

- Move initSideButtonChannel() call from initEnv() in main.dart to
  the InputModel constructor, removing the circular import between
  main.dart and input_model.dart
- Skip check_x11_button_map() when DISPLAY is not set to avoid
  noisy warnings on pure Wayland environments
2026-04-25 12:46:05 +08:00
Nawer
03e351ac61 feat(i18n): Complete and fix french translations (#14890) 2026-04-24 18:38:34 +08:00
fufesou
6cb323725b fix(sicter): control side, privacy mode (#14880)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-04-24 14:35:58 +08:00
Aliaksandr Kliujeŭ
5d0533f0d4 Update Balarusian strings (#14842)
* Update Balarusian strings

* BE: fix typos

* BE: fix ў-related typos
2026-04-23 23:52:43 +08:00
Re*Index. (ot_inc)
e0c5e1483e Update Japanese translate (#14838)
* Update ja.rs

* Update ja.rs

* Fix typo
2026-04-23 23:52:21 +08:00
Leo Louis
47e4c65d8e Update print statement from 'Hello' to 'Goodbye' (#14754) 2026-04-22 18:06:37 +08:00
Leo Louis
9bc1ce52af Add Malayalam language support (#14753)
* Add Malayalam language support

* Fix syntax error in language list for Malayalam

---------

Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2026-04-22 18:06:10 +08:00
Leo Louis
348d1b46e1 Add Hindi language support with translations (#14746)
* Add Hindi language support with translations

* Update print statement from 'Hello' to 'Goodbye'
2026-04-22 18:04:37 +08:00
Leo Louis
1a41b3ac11 Add Hindi language module and translation support (#14745)
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2026-04-22 18:04:09 +08:00
rustdesk
b239535009 refactor per code review 2026-04-22 01:41:13 +08:00
RustDesk
5fd20f808c fix safari-oidc https://github.com/rustdesk/rustdesk/issues/14861 (#14867) 2026-04-22 01:29:15 +08:00
rustdesk
803ac8cc4e save cargo build size 2026-04-21 17:34:05 +08:00
John Eismeier
4a50bc6fc2 Propose fix some typos (#14857)
Signed-off-by: John E <jeis4wpi@outlook.com>
2026-04-21 16:27:39 +08:00
fufesou
e8a1b7fe21 fix: build (#14846)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-04-20 10:05:32 +08:00
21pages
ac124c0680 flutter: improve address book pull error handling (#14813)
* flutter: improve address book pull error handling

Summary:
  - Show error messages when fetching the address book list fails.
  - After the initial fetch, switching back to the AB tab no longer re-fetches it, even if an error occurred or the error banner was dismissed.

  Tested:
  - Self-hosted server:
    - normal
    - 403 responses
    - legacy address book mode
  - Public server
  - Verified that switching tabs no longer re-fetches AB after the initial fetch, regardless of whether an error occurred or the error banner was cleared.

Signed-off-by: 21pages <sunboeasy@gmail.com>

* use resp.statusCode in address book json decoding

Signed-off-by: 21pages <sunboeasy@gmail.com>

* flutter: clear address book list errors on reset

Signed-off-by: 21pages <sunboeasy@gmail.com>

* flutter: clear address book pull errors consistently

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-04-18 11:19:32 +08:00
Luca-rickrolled-himself
91aff3ffd1 Complete and correct Romanian (ro) translations (#14837)
* Complete and correct Romanian (ro) translations

- Fill in all previously empty translation strings
- Fix plural form: "fișier" → "fișiere" (files)
- Fix "Receive" → "Primește" (was incorrectly using "Acceptă")
- Fix "Too frequent" → "Prea frecvent" (removed erroneous extra word)
- Fix "Note" → "Notă" (was translated as verb instead of noun)
- Fix "Use both passwords" → "Folosește ambele parole" ("programe" typo)
- Fix "Automatically record incoming sessions" → "sesiunile primite" (not "viitoare")
- Fix typo "neautoriztă" → "neautorizată" (Connection not allowed)
- Fix typo "dispozivul" → "dispozitivul" (Restart remote device)
- Fix leading whitespace in "Username" translation
- Fix "FPS" → keep as "FPS" (was incorrectly translated as "CPS")
- Fix "Forget Password" → "Parolă uitată" (command form was grammatically wrong)

* Fix typo in Romanian translation for accessibility tip

* unify informal register and fix subjunctive typo
2026-04-18 10:55:18 +08:00
John Fowler
642c281ad0 Update hu.rs (#14816)
New string translation and fixes.
2026-04-17 12:44:24 +08:00
fufesou
1e9c4d04f1 fix(mobile): deeplink, disable by default (#14824)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-04-16 23:21:14 +08:00
21pages
9f817714fe fix(client): stop retrying on restricted mobile access errors (#14797)
Treat "Access to mobile devices is restricted in your country"
  as a non-retriable connection error so the error dialog does not
  trigger reconnect attempts.

Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-04-15 21:40:03 +08:00
pallab-js
091f2c6135 impl(cm): implement change_theme and change_language callbacks (#14782)
* docs: fix typos in documentation and code comments

- Fix 'seperated' -> 'separated' in remote_input.dart
- Fix 'seperators' -> 'separators' in fuse/cs.rs
- Update outdated 'OSX' -> 'macOS' in virtual display README

Signed-off-by: pallab-js <sonowalpallabjyoti@gmail.com>

* impl(cm): implement change_theme and change_language callbacks

These callbacks were previously empty TODO stubs.
Now they properly invoke the Sciter UI handlers to notify
the UI when theme or language changes occur.

Signed-off-by: pallab-js <sonowalpallabjyoti@gmail.com>

---------

Signed-off-by: pallab-js <sonowalpallabjyoti@gmail.com>
2026-04-15 17:35:51 +08:00
rustdesk
91de51290d add microsoft oidc logo 2026-04-15 14:39:46 +08:00
rustdesk
68fa0466c8 improved oidc login error 2026-04-15 14:36:03 +08:00
Leo Louis
28e303576c Add support for Gujarati language in lang.rs (#14751) 2026-04-14 14:21:27 +08:00
Leo Louis
2d41b3e80d Add Gujarati language support with translations (#14752) 2026-04-14 14:21:10 +08:00
Andrzej Rudnik
ffd2d26c1a Update pl.rs (#14775) 2026-04-14 14:20:35 +08:00
Leo Louis
a8dc6fc632 Fix capture method return type in Recorder trait (#14748) 2026-04-13 13:04:43 +08:00
Leo Louis
771cb4ebd7 Update capture function return type for PixelProvider (#14747) 2026-04-13 13:03:35 +08:00
fufesou
2f694c0eb2 fix: file transfer, path traversal (#14678)
* fix: file transfer, path traversal

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

* fix(fs): remove stale files

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

* fix(fs): update_folder_files() after set_files()

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

* fix(fs): reduce .clone()

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

* fix(fs): undo checking "done message for unkown id"

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

* fix(fs): refactor

1. Hide `files` in `new_write()`.
2. Use `set_files()` to validate `files` before writing.

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

* fix(fs): comments

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

* fix(fs): Remove redundant checks

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

* fix(fs): update hbb_common

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-04-10 18:00:11 +08:00
21pages
8dea347a21 add brute-force protection for one-time password (#14682)
* add brute-force protection for temporary password

  Rotate the temporary password after repeated failed login attempts
  within one minute, and reset the failure window after successful
  authentication.

Signed-off-by: 21pages <sunboeasy@gmail.com>

* replace LazyLock with lazy_static

Signed-off-by: 21pages <sunboeasy@gmail.com>

* read temporary password after locking failure state

Signed-off-by: 21pages <sunboeasy@gmail.com>

* server: rotate temporary passwords after 10 consecutive failures

Signed-off-by: 21pages <sunboeasy@gmail.com>

* server: clarify temporary password failure counter comment

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-04-09 17:14:21 +08:00
rustdesk
0cf3e8ed40 improve agent md 2026-04-09 15:12:57 +08:00
21pages
9d3bc7d9e6 fix switch sides for macOS peers (#14661)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-04-07 23:39:24 +08:00
🌐 Qusai ALBahri 🌱
e0427bdc77 Translate UI strings to Arabic in ar.rs (#14694) 2026-04-06 18:27:14 +08:00
fufesou
9cf1338dc4 fix(win): exe icon path (#14686)
* fix(win): exe icon path

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

* fix(win): Simple refactor

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-04-04 22:54:13 +08:00
RustDesk
4e30ee8d1c tcp proxy (#14633)
* tcp proxy

* fix per review

* fix per review

* Suppress secure_tcp info logs for TCP proxy requests

Signed-off-by: 21pages <sunboeasy@gmail.com>

* copilot review: redact tcp proxy logs, dedupe headers, and avoid body clone

Signed-off-by: 21pages <sunboeasy@gmail.com>

* format common.rs

Signed-off-by: 21pages <sunboeasy@gmail.com>

* copilot review: test function name

Signed-off-by: 21pages <sunboeasy@gmail.com>

* copilot review: format IPv6 tcp proxy log targets correctly

Signed-off-by: 21pages <sunboeasy@gmail.com>

* copilot review: normalize HTTP method before direct request dispatch

Signed-off-by: 21pages <sunboeasy@gmail.com>

* review: extract fallback helper, fix Content-Type override, add overall timeout

- Extract duplicated TCP proxy fallback logic into generic
  `with_tcp_proxy_fallback` helper used by both `post_request` and
  `http_request_sync`, eliminating code drift risk
- Allow caller-supplied Content-Type to override the default in
  `parse_simple_header` instead of silently dropping it
- Take body by reference in `post_request_http` to avoid eager clone
  when no fallback is needed
- Wrap entire `tcp_proxy_request` flow (connect + handshake + send +
  receive) in an overall timeout to prevent indefinite stalls

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* review: make is_public case-insensitive and cover mixed-case rustdesk URLs

Signed-off-by: 21pages <sunboeasy@gmail.com>

* oidc: route auth requests through shared HTTP/tcp-proxy path while keeping TLS warmup

Signed-off-by: 21pages <sunboeasy@gmail.com>

* refactor: replace unused TryFrom<Response> with HbbHttpResponse::parse method

  Remove TryFrom<Response> impl that was never called and replace the
  private parse_hbb_http_response helper in account.rs with a public
  parse() method on HbbHttpResponse, eliminating code duplication.

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
Co-authored-by: 21pages <sunboeasy@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 23:13:05 +08:00
Alex Rijckaert
cca6a5fe12 Update Dutch translations (#14654) 2026-04-01 18:10:39 +08:00
VenusGirl❤
9e4b7fca4d Update Korean (#14644) 2026-03-31 21:34:35 +08:00
XLion
d135c58ead Update tw.rs (#14643) 2026-03-31 21:26:00 +08:00
Mr-Update
de194417d4 Update de.rs (#14640) 2026-03-31 21:25:05 +08:00
solokot
d01ce3173f Update ru.rs (#14636) 2026-03-30 22:37:35 +08:00
bilimiyorum
010a54d1c9 Update tr.rs (#14628)
New string entries
2026-03-29 23:02:53 +08:00
bovirus
f557fc94fa Italian language update (#14626) 2026-03-28 13:02:09 +08:00
21pages
f02cd9c0f6 Fix Windows session-based logon and lock-screen detection (#14620)
* Fix Windows session-based logon and lock-screen detection

  - scope LogonUI and locked-state checks to the current Windows session
  - allow permanent password fallback for logon and lock-screen access

Signed-off-by: 21pages <sunboeasy@gmail.com>

* Log permanent-password fallback on logon screen

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-03-27 13:22:16 +08:00
fufesou
170516572e refact(password): Store permanent password as hashed verifier (#14619)
* refact(password): Store permanent password as hashed verifier

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

* fix(password): remove unused code

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

* fix(password): mobile, password dialog, width 500

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-03-26 14:49:54 +08:00
fufesou
285e29d2dc fix(shell): check kv in update_install_option (#14564)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-03-26 12:08:29 +08:00
rustdesk
aab34b2338 remove winget 2026-03-25 16:36:35 +08:00
rustdesk
ad1e5330e9 update hbb_common 2026-03-24 20:39:44 +08:00
bovirus
ca4647ddd6 Italian language update (#14598) 2026-03-23 13:48:34 +08:00
Mr-Update
7004acae46 Update de.rs (#14572) 2026-03-21 16:18:56 +08:00
solokot
899dd46f5b Update ru.rs (#14570) 2026-03-21 16:18:39 +08:00
linsui
dba5fea66f Fix F-Droid 1.4.6 build (#13601)
* build_fdroid.sh: avoid using github api

* build_fdroid.sh: Find correct LLVM path for LLVM > 15.x

Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>

* build_fdroid.sh: formatting / spelling

Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>

---------

Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
Co-authored-by: Vasyl Gello <vasek.gello@gmail.com>
2026-03-20 13:45:35 +08:00
21pages
c457b0e7d3 add option to hide stop-service when service is running (#14563)
* add option to hide stop-service when service is running

Signed-off-by: 21pages <sunboeasy@gmail.com>

* update hbb_common to upstream

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-03-19 20:04:10 +08:00
Lynilia
c0da4a6645 Update fr.rs (#14567) 2026-03-18 22:53:30 +08:00
Qusai Ismael
9d8df6a226 Fix(wayland): improve error message when xdg-desktop-portal is unavailable #12897 (#14543)
* Fix: Wayland requires higher version of linux distro. Please try X11 desktop or change your OS. #12897

* refactor(wayland): optimize translation keys for binary size and improve dbus matching
2026-03-17 13:37:20 +08:00
Copilot
02da7132e7 Fix: note dialog not shown when closing session from reconnecting screen (#14528)
* Initial plan

* Fix: show ask-for-note dialog when user clicks OK on reconnecting screen (#14527)

Co-authored-by: rustdesk <71636191+rustdesk@users.noreply.github.com>

* fix: don't clear audit_guid during reconnect, clear it after connection established

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: rustdesk <71636191+rustdesk@users.noreply.github.com>
Co-authored-by: 21pages <sunboeasy@gmail.com>
2026-03-16 18:27:39 +08:00
rustdesk
e3b6e4eaf0 update tray icon crate to fix icon conflict 2026-03-14 15:54:54 +08:00
RustDesk
0388d00ad3 Revert "Update tray-icon crate to fix Linux tray icon collision (#14530)" (#14538)
This reverts commit 1e2d2c5146.
2026-03-14 14:49:55 +08:00
Eric Blanquer
1e2d2c5146 Update tray-icon crate to fix Linux tray icon collision (#14530)
Bump tray-icon from 0.14.3 to 0.21.3 which includes the fix
from tauri-apps/tray-icon#290 that derives the icon id from the
process id, preventing icon collisions between apps using the
same crate (e.g. Synergy, R-Quick-Share).

Refs: https://github.com/rustdesk/rustdesk/discussions/14165
2026-03-14 14:48:20 +08:00
rustdesk
96797742f2 fix https://github.com/rustdesk/rustdesk/issues/14520 2026-03-13 10:42:13 +08:00
Vasyl Gello
682e347be0 Bump Android NDK to r28c (#13685)
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2026-03-12 16:52:33 +08:00
fufesou
b3f43f55c1 fix(mobile): restore canvas offset after hidding the soft keyboard (#14506)
* fix(mobile): restore canvas offset after hidding the soft keyboard

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

* fix(mobile): ingore mobileFocusCanvasCursor in didChangeMetrics

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

* fix(mobile): remove unused code

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

* refact(mobile): simple refactor

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

* fix(mobile): restore canvas, cancel focus timer

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-03-11 18:28:37 +08:00
21pages
016a0b1141 fix strategy cannot apply over default advanced options (#14502)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-03-10 13:24:13 +08:00
John Fowler
fd7bcf54bd Hungarian language file update (#14497)
* Update Hungarian translations in hu.rs

Translation of new strings and some fixes.
John Fowler.

* Escape quotes in Hungarian language strings

Replacing Hungarian quotation marks

* Update Hungarian translations for various terms

Upload a new translation (hu.rs) file.

* Hungarian language file correction

New character strings translation, error correction.

* Hungarian language file update

New string translations.
2026-03-09 21:28:37 +08:00
layla
db3f5fe816 Fix typo: Rustdesk to RustDesk in Russian README (#14468) 2026-03-08 19:18:59 +08:00
fufesou
0d3016fcd8 fix(flutter): reduce accidental horizontal trackpad scrolling during vertical pan (#14460)
* fix(flutter): reduce accidental horizontal trackpad scrolling during vertical pan

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

* refact: comments

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-03-05 23:10:39 +08:00
21pages
1abc897c45 fix avatar fallback (#14458)
* fix avatar fallback

Signed-off-by: 21pages <sunboeasy@gmail.com>

* fix(ui): improve avatar fallback handling and layout consistency

  - Always show spacing in account section regardless of avatar presence
  - Handle null return from buildAvatarWidget with proper fallback
  - Adjust mobile settings avatar size to 28

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-03-05 12:30:40 +08:00
RustDesk
ab64a32f30 avatar (#14440)
* avatar

* refactor avatar display: unify rendering and resolve at use time

  - Extract buildAvatarWidget() in common.dart to share avatar rendering
    logic across desktop settings, desktop CM and mobile CM
  - Add resolve_avatar_url() in Rust, exposed via FFI (SyncReturn),
    to resolve relative avatar paths (e.g. "/avatar/xxx") to absolute URLs
  - Store avatar as-is in local config, only resolve when displaying
    (settings page) or sending (LoginRequest)
  - Resolve avatar in LoginRequest before sending to remote peer
  - Add error handling for network image load failures
  - Guard against empty client.name[0] crash
  - Show avatar in mobile settings page account tile

Signed-off-by: 21pages <sunboeasy@gmail.com>

* web: implement mainResolveAvatarUrl via js getByName

Signed-off-by: 21pages <sunboeasy@gmail.com>

* increase ipc Data enum size limit to 120 bytes

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
Co-authored-by: 21pages <sunboeasy@gmail.com>
2026-03-04 21:43:19 +08:00
RustDesk
52b66e71d1 Move port mapping afterwards (#14448)
* move port mapping after auth in port forwarding

* fix(port-forward): try connect after 2fa

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

* fix(security): gate port-forward connect on full auth and clarify login flow semantics

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

* refact(port-forward): comments and logs

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: fufesou <linlong1266@gmail.com>
2026-03-04 15:48:42 +08:00
fufesou
41ab5bbdd8 fix(update): macos, test before update (#14446)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-03-03 10:47:32 +08:00
fufesou
732b250815 fix(keyboard): legacy mode (#14435)
* fix(keyboard): legacy mode

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

* Simple refactor

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

* fix(keyboard): legacy mode, chr to seq

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

* fix(keyboard): legacy mode, early return if (!hotkey)&down

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

* fix(keyboard): legacy mode, pair down/up

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-03-02 19:07:09 +08:00
rustdesk
157dbdc543 fix avatar in hbb_common 2026-03-02 12:14:26 +08:00
rustdesk
6ba23683d5 avatar in libs/hbb_comon 2026-03-02 12:06:20 +08:00
fufesou
80a5865db3 macOS update: restore LaunchAgent in GUI session and isolate temp update dir by euid (#14434)
* fix(update): macos, load agent

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

* fix(update): macos, isolate temp update dir by euid

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

* refact(update): macos script

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-03-01 20:06:04 +08:00
MichaIng
9cb6f38aea packaging: deb: remove obsolete Python version check (#14429)
It was used to conditionally install a Python module in the past. But that is not the case anymore since https://github.com/rustdesk/rustdesk/commit/37dbfcc. Now the check is obsolete.

Due to `set -e`, the check leads to a package configuration failure if Python is not installed, which however otherwise is not needed for RustDesk.

The commit includes an indentation fix and trailing space removal.

Signed-off-by: MichaIng <micha@dietpi.com>
2026-03-01 18:05:19 +08:00
fufesou
cd7e3e4505 fix(update): macos, input password (#14430)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-03-01 15:19:07 +08:00
fufesou
1833cb0655 fix(update): revert check (#14424)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-02-28 18:17:26 +08:00
fufesou
e4208aa9cf fix(update): revert check (#14423)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-02-28 16:33:54 +08:00
Amirhosein Akhlaghpoor
bb3501a4f9 ui: scale wheel lines on Windows/Linux to Mac (#14395)
* input: accelerate wheel bursts on Windows->Mac

- boost fast wheel bursts without affecting single-step scrolls\n- use dominant-axis smooth detection and velocity gate\n- reset wheel timestamp on enter/leave\n- enforce single-axis scrolling\n- extract/tune Sciter wheel accel thresholds

Signed-off-by: Amirhossein Akhlaghpour <m9.akhlaghpoor@gmail.com>

* input: clarify wheel burst tuning

- add comments on acceleration rules and units\n- apply burst accel on Windows/Linux to macOS\n- reset wheel timing on enter/leave

Signed-off-by: Amirhossein Akhlaghpour <m9.akhlaghpoor@gmail.com>

* input: align wheel burst velocity thresholds

- match Flutter velocity gate with Sciter

Signed-off-by: Amirhossein Akhlaghpour <m9.akhlaghpoor@gmail.com>

* input: restore flutter wheel velocity threshold

- keep burst threshold at 0.002 delta/us

Signed-off-by: Amirhossein Akhlaghpour <m9.akhlaghpoor@gmail.com>

---------

Signed-off-by: Amirhossein Akhlaghpour <m9.akhlaghpoor@gmail.com>
2026-02-28 10:56:25 +08:00
fufesou
4abdb2e08b feat: windows, custom client, update (#13687)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-02-27 21:50:20 +08:00
rustdesk
d49ae493b2 bump to 1.4.6 2026-02-27 20:53:40 +08:00
VenusGirl❤
394079833e Update ko.rs (#14418) 2026-02-27 20:14:14 +08:00
Alex Rijckaert
12d6789c2e Update translation (#14413) 2026-02-27 12:09:47 +08:00
memory_clear
34803f8e9b Update labels for keep awake during sessions (#14391) 2026-02-26 18:28:19 +08:00
solokot
fd43184406 Update ru.rs (#14386) 2026-02-26 18:28:09 +08:00
Mr-Update
3cc3315081 Update de.rs (#14385) 2026-02-26 18:27:58 +08:00
RustDesk
6aee70fa18 fix https://github.com/rustdesk/rustdesk/issues/609#issuecomment-3931613118 (#14364) 2026-02-25 17:09:51 +08:00
rustdesk
82a9fd1540 change port forward listen to localhost 2026-02-24 21:57:55 +08:00
rustdesk
dc760d6ca8 remove .claude 2026-02-24 21:52:26 +08:00
Amirhosein Akhlaghpoor
eb239501bc Fix logon-screen password with click approval (#14335) 2026-02-24 21:14:18 +08:00
fufesou
0016033937 feat(terminal): add reconnection buffer support for persistent sessions (#14377)
* feat(terminal): add reconnection buffer support for persistent sessions

Fix two related issues:
1. Reconnecting to persistent sessions shows blank screen - server now
   automatically sends historical buffer on reconnection via SessionState
   machine with pending_buffer, eliminating the need for client-initiated
   buffer requests.
2. Terminal output before view ready causes NaN errors - buffer output
   chunks on client side until terminal view has valid dimensions, then
   flush in order on first valid resize.

Rust side:
- Introduce SessionState enum (Closed/Active) replacing bool is_opened
- Auto-attach pending buffer on reconnection in handle_open()
- Always drain output channel in read_outputs() to prevent overflow
- Increase channel buffer from 100 to 500
- Optimize get_recent() to collect whole chunks (avoids ANSI truncation)
- Extract create_terminal_data_response() helper (DRY)
- Add reconnected flag to TerminalOpened protobuf message

Flutter side:
- Buffer output chunks until terminal view has valid dimensions
- Flush buffered output on first valid resize via _markViewReady()
- Clear terminal on reconnection to avoid duplicate output from buffer replay
- Fix max_bytes type (u32) to match protobuf definition
- Pass reconnected field through FlutterHandler event

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

* fix(terminal): add two-phase SIGWINCH for TUI app redraw and session remap on reconnection

Fix TUI apps (top, htop) not redrawing after reconnection. A single
resize-then-restore is too fast for ncurses to detect a size change,
so split across two read_outputs() polling cycles (~30ms apart) to
force a full redraw.

Also fix reconnection failure when client terminal_id doesn't match
any surviving server-side session ID by remapping the lowest surviving
session to the requested ID.

Rust side:
- Add two-phase SIGWINCH state machine (SigwinchPhase: TempResize →
  Restore → Idle) with retry logic (max 3 attempts per phase)
- Add do_sigwinch_resize() for cross-platform PTY resize (direct PTY
  and Windows helper mode)
- Add session remap logic for non-contiguous terminal_id reconnection
- Extract try_send_output() helper with rate-limited drop logging (DRY)
- Add 3-byte limit to UTF-8 continuation byte skipping in get_recent()
  to prevent runaway on non-UTF-8 binary data
- Remove reconnected flag from flutter.rs (unused on client side)

Flutter side:
- Add reconnection screen clear and deferred flush logic
- Filter self from persistent_sessions restore list
- Add comments for web-related changes

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-02-24 21:12:06 +08:00
bilimiyorum
50c62d5eac Update tr.rs (#14376)
New string entry
2026-02-24 16:30:32 +08:00
Lynilia
91ac48912e Update fr.rs (#14383) 2026-02-24 16:30:12 +08:00
John Fowler
272a6604cd Hungarian language file correction (#14382)
* Update Hungarian translations in hu.rs

Translation of new strings and some fixes.
John Fowler.

* Escape quotes in Hungarian language strings

Replacing Hungarian quotation marks

* Update Hungarian translations for various terms

Upload a new translation (hu.rs) file.

* Hungarian language file correction

New character strings translation, error correction.
2026-02-24 16:29:54 +08:00
westor
8a889d3ebb Update el.rs translation (#14378)
- Added missing language strings.
- Fixed some previously typo translations.
- Updated some translation strings.
2026-02-24 16:29:43 +08:00
bovirus
17a3f2ae52 Italian language update (#14375) 2026-02-23 16:37:53 +08:00
RustDesk
6c3515588f - UI display: display_name first (#14358)
* - UI display: display_name first
  - Fallback: name
  - Technical identity: still name

  ### What changed

  - Added account display helpers and display_name state in user model:
      - flutter/lib/models/user_model.dart:16
  - Account/logout label now uses display_name (@name) when both exist:
      - flutter/lib/mobile/pages/settings_page.dart:689
      - flutter/lib/desktop/pages/desktop_setting_page.dart:2016
      - flutter/lib/desktop/pages/desktop_setting_page.dart:2135
  - Desktop Account info now shows both when applicable:
      - Display Name: ...
      - Username: ...
      - flutter/lib/desktop/pages/desktop_setting_page.dart:2039
  - Previously done group-list behavior remains:
      - group user list displays display_name with name fallback
      - flutter/lib/common/widgets/my_group.dart:187
  - Persistence path for display_name remains enabled (including group cache/submodule field):
      - libs/hbb_common/src/config.rs:2347
  - src/client.rs:2630
  - LoginRequest.my_name now resolves as:
      1. OPTION_DISPLAY_NAME (manual override)
      2. user_info.display_name
      3. user_info.name
      4. OS username fallback

* 1. GUID key (...Uninstall\{GUID}) is MSI-native metadata generated by Windows Installer.
  2. Non-GUID key (...Uninstall\RustDesk) is explicitly written by RustDesk’s MSI compatibility component in res/msi/Package/Components/Regs.wxs:44, populated by preprocess.py --arp from .github/workflows/
     flutter-build.yml:262.

  So they were not using the same EstimatedSize logic:

  - MSI GUID key: MSI-calculated size (KB).
  - RustDesk key: custom script value from res/msi/preprocess.py:339 (previously bytes, now fixed to KB).

  That mismatch is exactly why you saw different sizes.

* improve display name handling

  - Append (@username) when multiple users share the same display name
  - Trim whitespace from display_name before comparison and display
  - Add missing translate() for Logout button on desktop

Signed-off-by: 21pages <sunboeasy@gmail.com>

* group peer filter match both user's display name and user's name

Signed-off-by: 21pages <sunboeasy@gmail.com>

* case-insensitive search in group peer filter

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
Co-authored-by: 21pages <sunboeasy@gmail.com>
2026-02-22 14:59:25 +08:00
fufesou
4d2d2118a2 Fix/terminal tab close persistent (#14359)
* fix(terminal): ensure tab close is resilient to session cleanup failures

- Wrap _closeTerminalSessionIfNeeded in isolated try/catch so that
  tabController.closeBy always executes even if FFI calls throw
- Add clarifying comment in handleWindowCloseButton for single-tab
  audit dialog flow

* fix(terminal): fix session reconnect ID mismatch and tab close race condition

Remap surviving persistent sessions to client-requested terminal IDs on
reconnect, preventing new shell creation when IDs are non-contiguous.
Snapshot peerTabCount before async operations in _closeTab to avoid race
with concurrent _closeAllTabs clearing the tab controller.
Remove debug log statements.

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-02-21 11:06:13 +08:00
fufesou
483fe80308 fix(terminal): fix new tab auto-focus and NaN error on data before layout (#14357)
- Fix new tab not auto-focusing: add FocusNode to TerminalView and
  request focus when tab is selected via tab state listener
- Fix NaN error when data arrives before terminal view layout: buffer
  output data until terminal view has valid dimensions, flush on first
  valid resize callback

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-02-20 14:44:25 +08:00
fufesou
34ceeac36e fix(terminal): fix tabKey parsing for peerIds containing underscores (#14354)
Terminal tab keys use the format "peerId_terminalId". The previous code
used split('_')[0] or startsWith('$peerId_') to extract the peerId,
which breaks when the peerId itself contains underscores.

This can happen in two scenarios:
- Hostname-based ID: when OPTION_ALLOW_HOSTNAME_AS_ID is enabled, the
  peerId is derived from the system hostname, which commonly contains
  underscores (e.g. "my_dev_machine").
- Custom ID: the validation regex ^[a-zA-Z][\w-]{5,15}$ allows
  underscores since \w matches [a-zA-Z0-9_], so IDs like "my_dev_01"
  are valid.

Fix all three parsing sites in terminal_tab_page.dart to use
lastIndexOf('_'), which is safe because terminalId is always a plain
integer with no underscores.
2026-02-19 23:45:06 +08:00
cui
20f11018ce fix: lte should be lt like in linux.rs (#14344) 2026-02-19 22:24:32 +08:00
Nicola Spieser Buiss
9345fb754a fix: correct typos and improve code clarity (#14341)
- Fix 'clipbard' typos in clipboard.rs (function names, comments, strings)
- Fix 'seperate' typo in x11/server.rs comment
- Replace !is_ok() with idiomatic is_err() in updater.rs
- Fix double backtick typo in updater.rs comment

Co-authored-by: Ocean <ocean@Mac-mini-von-Ocean.local>
2026-02-17 14:29:50 +08:00
fufesou
779b7aaf02 feat(wayland): keyboard mode, legacy translate (#14317)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-02-15 16:43:21 +08:00
21pages
b268aa1061 Fix some single device multiple ids scenarios on MacOS (#14196)
* fix(macos): sync config to root when root config is empty

Signed-off-by: 21pages <sunboeasy@gmail.com>

* fix(server): gate startup on initial config sync; document CheckIfResendPk limitation

  - wait up to 3s for initial root->local config sync before starting server services
  - continue startup when timeout is hit, while keeping sync/watch running in background
  - avoid blocking non-server process startup
  - clarify that CheckIfResendPk only re-registers PK for current ID and does not solve multi-ID when root uses a non-default mac-generated ID

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-02-15 16:12:26 +08:00
Vance
40f86fa639 fix(mobile): account for safe area padding in canvas size calculation (#14285)
* fix(mobile): account for safe area padding in canvas size calculation

* fix(mobile): differentiate safe area handling for portrait vs landscape

* refact(ios): Simple refactor

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

* fix(ios): canvas getSize, test -> Android

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

* fix: comments

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: fufesou <linlong1266@gmail.com>
2026-02-15 14:52:27 +08:00
rustdesk
980bc11e68 update common 2026-02-14 17:48:53 +08:00
Shaikh Naasir
85db677982 docs: fix typos in clipboard documentation (#13521)
Signed-off-by: Naasir <yoursdeveloper@protonmail.com>
2026-02-14 01:06:25 +08:00
fufesou
2842315b1d Fix/linux shortcuts inhibit (#14302)
* feat: Inhibit system shortcuts on Linux

Fixes #13013.

Signed-off-by: Max von Forell <max@vonforell.de>

* fix(linux): shortcuts inhibit

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

---------

Signed-off-by: Max von Forell <max@vonforell.de>
Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: Max von Forell <max@vonforell.de>
2026-02-11 16:11:47 +08:00
fufesou
6c541f7bfd fix(xdo): deb, libxdo3 | libxdo4 (#14314)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-02-11 16:11:15 +08:00
VenusGirl❤
067fab2b73 Update Korean (#14298)
Correct spacing and spelling
2026-02-10 18:48:30 +08:00
fufesou
de6bf9dc7e fix(ios): Add defensive timer cancellation for keyboard visibility (#14301)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-02-09 15:54:22 +08:00
fufesou
54eae37038 fix(ios): workaround physical keyboard after virtual keyboard hidden (#14207)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-02-09 00:36:25 +08:00
Hugo Breda
0118e16132 PT-BR language update (#14295)
* PT-BR language update

@rustdesk
Please merge. Thanks

* Update ptbr.rs

* Update ptbr.rs

Please submit, i will get back soon and finish all other stuff.

* PT-BR language update

Completed all missing PT-BR translations.
2026-02-09 00:31:47 +08:00
fufesou
626a091f55 fix(translation): OIDC, Continue with (#14271)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-02-06 14:18:48 +08:00
Daniel Marschall
4fa5e99e65 Remove unused option_env!(...) (#13959) 2026-02-03 20:55:34 +08:00
bilimiyorum
5ee9dcf42d Update tr.rs (#14160)
The previous PR was reverted due to an incorrect file path. This PR applies the same updates to src/lang/tr.rs.
2026-02-02 22:18:36 +08:00
Copilot
6306f83316 Fix non-link text color in dialogs with links for dark theme (#14220)
* Initial plan

* Fix dialog text color for dark theme with links

Co-authored-by: rustdesk <71636191+rustdesk@users.noreply.github.com>

* Keep original link color (blue), only fix non-link text color

Co-authored-by: rustdesk <71636191+rustdesk@users.noreply.github.com>

* fix: dialog text color in dark theme

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: rustdesk <71636191+rustdesk@users.noreply.github.com>
Co-authored-by: fufesou <linlong1266@gmail.com>
2026-02-01 12:18:07 +08:00
XLion
96075fdf49 Update tw.rs (#14138) 2026-01-31 16:38:09 +08:00
Copilot
8c6dcf53a6 iOS terminal: Add touch swipe and floating back button for exit (#14208)
* Initial plan

* Add iOS edge swipe gesture to exit terminal session

Co-authored-by: rustdesk <71636191+rustdesk@users.noreply.github.com>

* Improve iOS edge swipe gesture with responsive thresholds and better gesture handling

Co-authored-by: rustdesk <71636191+rustdesk@users.noreply.github.com>

* Fix: Reset _swipeCurrentX in onHorizontalDragStart to prevent stale state

Co-authored-by: rustdesk <71636191+rustdesk@users.noreply.github.com>

* Add trackpad support documentation for iOS edge swipe gesture

Co-authored-by: rustdesk <71636191+rustdesk@users.noreply.github.com>

* Add iOS-style circular back button to terminal page

Co-authored-by: rustdesk <71636191+rustdesk@users.noreply.github.com>

* Remove trackpad support documentation - not needed with back button

Co-authored-by: rustdesk <71636191+rustdesk@users.noreply.github.com>

* Filter edge swipe gesture to touch-only input (exclude mouse/trackpad)

Co-authored-by: rustdesk <71636191+rustdesk@users.noreply.github.com>

* fix: missing import

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

* fix(ios): terminal swip exit gesture

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

* Update flutter/lib/mobile/pages/terminal_page.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: rustdesk <71636191+rustdesk@users.noreply.github.com>
Co-authored-by: fufesou <linlong1266@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-31 16:37:45 +08:00
fufesou
e1b1a927b8 fix(ios): capsLock, workaround #5871 (#14194)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-01-30 17:32:18 +08:00
fufesou
1e6bfa7bb1 fix(iPad): Magic Mouse, click (#14188)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-01-29 15:25:44 +08:00
fufesou
79ef4c4501 Copilot/fix action run error (#14186)
* Initial plan

* Fix macOS build: Remove @available check causing linker error

The @available check in GetDisplayName was causing the linker to look for
__isPlatformVersionAtLeast symbol which is not available when targeting
macOS 10.14. Since this function is only used for logging, we simplify it
to return "Unknown" for all displays, avoiding the runtime availability check.

Co-authored-by: rustdesk <71636191+rustdesk@users.noreply.github.com>

* fix(macOS): ___isPlatformVersionAtLeast is not available in macOS 10.14

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: rustdesk <71636191+rustdesk@users.noreply.github.com>
2026-01-28 17:44:17 +08:00
twprh
5f3ceef592 Update de.rs (#14139)
zum Zeitpunkt der Anzeige ist der Datenschutz aktiviert bzw. schon beendet.

alternativ ginge auch:

Datenschutzmodus wurde aktiviert  
bzw.
 Datenschutzmodus wurde beendet
2026-01-28 15:16:27 +08:00
Lynilia
1a90e6b6c7 Update fr.rs (#14151) 2026-01-28 15:16:06 +08:00
John Fowler
f112d097dc Replacing incorrect quotation marks (#14144)
* Update Hungarian translations in hu.rs

Translation of new strings and some fixes.
John Fowler.

* Escape quotes in Hungarian language strings

Replacing Hungarian quotation marks

* Update Hungarian translations for various terms

Upload a new translation (hu.rs) file.
2026-01-28 15:15:29 +08:00
ThallesWS
45cab7f808 fix issue: #13911 'Double Click' bug on iPad with Magic Mouse (#14086)
* fix issue: #13911 'Double Click' bug on iPad with Magic Mouse

* remote_input.dart comments - gestures.dart organization and clean states of all interrupted gestures
2026-01-28 15:14:06 +08:00
fufesou
216ec9d52b fix(terminal): ios delete (#14147)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-01-28 15:12:42 +08:00
fufesou
56a8f6b97b fix(iOS): Unexpected mouse movement to (0,0) on idle (#14180)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-01-28 15:11:44 +08:00
Bin Li
c76d10a438 feat(macos): initial privacy mode support [a simple try] (#14102)
* feat(macos): add privacy mode support for macOS

## Summary
Add privacy mode functionality for macOS platform, allowing remote
desktop sessions to hide the screen content from local users.

## Changes

### Core Implementation (src/platform/macos.mm)
- Implement screen blackout using CGDisplayGammaTable API
- Implement input blocking using CGEventTap to intercept keyboard/mouse
- Store and restore original gamma values for proper cleanup

### Privacy Mode Integration (src/privacy_mode.rs, src/privacy_mode/macos.rs)
- Add macOS privacy mode implementation with PrivacyMode trait
- Register macOS privacy mode in PRIVACY_MODE_CREATOR
- Set DEFAULT_PRIVACY_MODE_IMPL for macOS platform
- Implement get_supported_privacy_mode_impl() for macOS

### Connection Handling (src/server/connection.rs)
- Add supported_privacy_mode_impl to platform_additions for macOS
- Enable privacy mode toggle in client UI when connecting via LAN IP

### Localization (src/lang/*.rs)
- Add "privacy_mode_impl_macos_tip" translation for en/cn/tw

## Safety & Security
- Implements Drop trait to ensure cleanup on normal exit
- macOS system automatically restores gamma table on process termination
- CGEventTap is automatically released when process terminates
- Tested with SIGKILL to verify crash recovery

## Testing
- Verified privacy mode toggle works via both ID and LAN IP connection
- Verified screen recovery after process crash (kill -9)
- Verified input restoration after process termination

* refactor: use existing 'Privacy mode' translation key

* refactor: rename gamma channel variables for better readability - rename r/g/b to red/green/blue to avoid variable shadowing confusion

* fix: add error handling for gamma table restoration with fallback to system reset

* fix: add error handling for CGEventTapCreate failure in privacy mode

* fix: only set display to black if original gamma was saved successfully

* fix: add error handling for CGSetDisplayTransferByTable when setting display to black

* fix: improve event tap callback to properly distinguish remote input from local input

* fix: missing macos.rs

* Fix: Add display validation before restoring gamma values

* Fix: Add mutex lock for thread safety in MacSetPrivacyMode

* Fix: Handle return values and add missing mouse events in macos privacy mode

* fix: only set conn_id after privacy mode is successfully turned on

* fix: reimplement privacy mode with stable display identification

Address code review concern: original gamma values stored with DisplayID
as key could become stale if display list changes between privacy mode
activations (e.g., display reconnected with different ID).

Solution:
- Use UUID instead of DisplayID as storage key (stable across reconnections)
- Clear g_originalGammas when privacy mode is turned off
- Register CGDisplayReconfigurationCallback to handle hot-plug events
- Validate display state via FindDisplayIdByUUID() before restoration

Key features:
- UUID-based display identification (stable across reconnections)
- Hot-plug support via CGDisplayReconfigurationCallback
- EventTap auto re-enable on system timeout
- Fallback to CGDisplayRestoreColorSyncSettings() for recovery
- Detailed error logging with display name/ID/UUID

* fix: ensure EventTap runs on main thread and improve gamma restore error handling

- Add SetupEventTapOnMainThread() to create EventTap on main thread using dispatch_sync, avoiding potential issues when called from background threads

- Add TeardownEventTapOnMainThread() for consistent cleanup on main thread

- Check [NSThread isMainThread] to avoid deadlock when already on main thread

- Add error tracking for gamma restoration during cleanup

- Use CGDisplayRestoreColorSyncSettings() as fallback when individual gamma restoration fails

* fix: remove invalid eventMask bits that caused undefined behavior in input blocking

* fix: address code review comments for macos privacy mode implementation

Changes to src/privacy_mode/macos.rs:
- Add check_on_conn_id() in turn_on_privacy() to prevent duplicate activation
- Add check_off_conn_id() in turn_off_privacy() to validate connection ID
- Add self.conn_id = 0 in clear() to reset connection state

Changes to src/platform/macos.mm:
- Add link comment for ENIGO_INPUT_EXTRA_VALUE referencing libs/enigo/src/macos/macos_impl.rs
- Fix NSLog format string mismatch (5 placeholders vs 4 values)
- Make ApplyBlackoutToDisplay() return bool for proper error handling
- Return false when UUID is empty since privacy mode requires ALL displays
- Add else branches with logging for:
  - CGGetDisplayTransferByTable failures
  - Zero gamma table capacity (not supported)
  - Zero blackout capacity
- Remove unused g_uuidToDisplayId variable (was only written, never read)

* fix(macos): add early return with privacy mode exit on display hotplug failures

Why large-scale changes are needed:

The code review suggested adding early return when errors occur in
DisplayReconfigurationCallback. However, simply returning early is not
enough - when a newly connected display cannot be blacked out, we must
exit privacy mode entirely to maintain security guarantees.

The challenge is that DisplayReconfigurationCallback already holds
g_privacyModeMutex, so calling MacSetPrivacyMode(false) directly would
cause a deadlock. This necessitated:

1. Extract TurnOffPrivacyModeInternal() - a lock-free internal function
   that can be safely called from within the callback
2. Refactor MacSetPrivacyMode(false) branch to use this internal function
3. Add early returns with TurnOffPrivacyModeInternal() calls at each
   failure point in DisplayReconfigurationCallback

Changes in DisplayReconfigurationCallback:
- UUID empty: log + exit privacy mode + early return
- Gamma table capacity zero: log + exit privacy mode + early return
- CGGetDisplayTransferByTable fails: log + exit privacy mode + early return
- ApplyBlackoutToDisplay fails: log + exit privacy mode + early return

* fix(macos): address code review feedback and improve privacy mode stability

Code Review Fixes:
- Add detailed comments for potential deadlock scenarios in dispatch_sync
  with g_privacyModeMutex (SetupEventTapOnMainThread/TeardownEventTapOnMainThread)
- Use async dispatch for privacy mode shutdown from DisplayReconfigurationCallback
  to avoid unregistering callback from within itself
- Extract RestoreAllGammas() helper function to reduce code duplication
- Fix Drop implementation in macos.rs to call self.clear() for consistency
- Add comment explaining why _state parameter is ignored on macOS
- Define DISPLAY_RECONFIG_MONITOR_DURATION_MS and GAMMA_CHECK_INTERVAL_MS constants
- Add gamma restoration when UUID retrieval fails during privacy mode activation

Privacy Mode Stability Improvements (Continuous Resolution Changes):
- Implement continuous gamma value monitoring with timer polling after display
  reconfiguration to handle rapid successive resolution changes
- Monitor gamma values every 200ms for 5 seconds after each resolution change
- Automatically reapply blackout if system (ColorSync) restores gamma
- Add IsDisplayBlackedOut() to detect if display gamma has been restored
- Use timestamp-based debouncing: monitoring period automatically extends
  when new reconfig events occur during active monitoring
- Ensure blackout remains effective even under continuous resolution changes
  where macOS may asynchronously restore gamma values multiple times

This ensures privacy mode remains stable and effective when users rapidly
change display resolution multiple times in succession.

---------

Co-authored-by: libin <libin.chat@outlook.com>
2026-01-27 16:38:37 +08:00
Alex Rijckaert
f05f2178e5 Update Dutch translations (#14136) 2026-01-26 14:16:21 +08:00
Hugo Breda
226d7417b2 PT-BR language update (#14135)
* PT-BR language update

@rustdesk
Please merge. Thanks

* Update ptbr.rs

* Update ptbr.rs

Please submit, i will get back soon and finish all other stuff.
2026-01-26 14:15:58 +08:00
bovirus
b0c8e65c6e Italian language update (#14129) 2026-01-26 14:15:45 +08:00
RustDesk
4ae577c3c4 Revert "Updated tr.rs (#14115)" (#14158)
This reverts commit 204e81a700.
2026-01-26 14:14:35 +08:00
bilimiyorum
204e81a700 Updated tr.rs (#14115)
Translation improvements have been made.
2026-01-26 14:11:58 +08:00
hatterp
1f35830570 Update pl.rs (#14112)
updated PL translation
2026-01-26 14:11:41 +08:00
VenusGirl❤
6b334f2977 Update ko.rs (#14110)
Update Korean
2026-01-25 16:37:34 +08:00
Mr-Update
0dc3c12aa5 Update de.rs (#14108) 2026-01-24 12:50:18 +08:00
RustDesk
ceffcce20e fix hide-tray=Y causing The application “RustDesk.app” is not open anymore. https://github.com/rustdesk/rustdesk/discussions/10210 (#14127) 2026-01-23 19:09:33 +08:00
21pages
e4b06dadf5 auto retry on offline when already connected (#14124)
When controlled peer is reconnecting after signout/switch user, auto retry for 30s (matches server's peer offline threshold) instead of immediately showing "Remote desktop is offline" error.

Ref: https://github.com/rustdesk/rustdesk/discussions/14048

Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-01-23 15:05:11 +08:00
Yavuz Selim YAZICI
087eb55299 Update tr.rs, Missing Turkish translations added (#14103)
* Update tr.rs

* Update tr.rs

---------

Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2026-01-22 14:15:14 +08:00
bilimiyorum
341eb0c671 Updated tr.rs (#14100)
New string entries
Minor typo corrections
2026-01-22 14:13:38 +08:00
solokot
43b39102a4 Update ru.rs (#14099) 2026-01-22 14:12:26 +08:00
fufesou
be4bbd018d fix(install): linux xdo (#14096)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-01-21 20:43:15 +08:00
RustDesk
21a7cef98a keep-awake-during-incoming-sessions (#14082)
* keep-awake-during-incoming-sessions

* Update flutter/lib/desktop/pages/desktop_setting_page.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update flutter/lib/common.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update flutter/lib/mobile/pages/settings_page.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update common.dart

* wakelock

Signed-off-by: 21pages <sunboeasy@gmail.com>

* fix build

Signed-off-by: 21pages <sunboeasy@gmail.com>

* Update server_model.dart

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: 21pages <sunboeasy@gmail.com>
2026-01-21 16:25:57 +08:00
fufesou
a6724b1c07 fix: build (#14093)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-01-20 22:53:18 +08:00
Cody Kim
7437593ee7 Update ko.rs (#14055)
* update: correct Korean translations (typo/grammar)

- typo: 인중 -> 인증
- grammar: 중 입니다 -> 중입니다

Signed-off-by: 0-Chan <kyc4421194@gmail.com>

* update: improve Korean translations

Signed-off-by: 0-Chan <kyc4421194@gmail.com>

---------

Signed-off-by: 0-Chan <kyc4421194@gmail.com>
2026-01-20 17:08:54 +08:00
VenusGirl❤
f21829b075 Update Korean (#14057) 2026-01-20 17:08:02 +08:00
hatterp
b4f60e6057 Update pl.rs (#14054)
improve Polish translation

Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2026-01-19 13:41:10 +08:00
hatterp
b9ebddff0c Update pl.rs (#14053)
Add and improve Polish translation.
2026-01-18 19:34:26 +08:00
hatterp
a2243484a3 Update README-PL.md (#14052) 2026-01-17 18:31:41 +08:00
21pages
c4a9835ae5 change quick support filename detection (#14050)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-01-15 13:47:39 +08:00
Alex Rijckaert
92ad279324 Dutch Translation up to date (#14033) 2026-01-14 13:05:01 +08:00
Kratos
7276025cf9 Update hu.rs (#14032)
Fix translated strings.
2026-01-13 11:00:29 +08:00
minh
9808d585cf Update vi.rs file (#14027) 2026-01-13 11:00:16 +08:00
John Fowler
dab9ed711c Update Hungarian translations in hu.rs (#14014)
Translation of new strings and some fixes.
John Fowler.
2026-01-12 20:57:05 +08:00
Mr-Update
b27a93fc77 Update de.rs (#14013) 2026-01-12 20:56:50 +08:00
Lynilia
e3f66973b7 Update fr.rs (#14012) 2026-01-12 20:56:35 +08:00
bilimiyorum
21529d6ca2 Current tr.rs (#14008)
New string entries
2026-01-12 20:56:19 +08:00
solokot
775b0a3c93 Update ru.rs (#14004) 2026-01-12 20:56:02 +08:00
Anatolij Vasilev
070d4d029f synchronized german translation with the current english readme (#14001) 2026-01-12 10:59:11 +08:00
bovirus
5355702e9c Italian language update (#13998) 2026-01-12 10:58:42 +08:00
VenusGirl❤
a97997952d Update Korean (#13996)
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2026-01-12 10:58:23 +08:00
Sunev
b0c12bd86b Update signing conditions for rustdesk files (#14010)
Now ```env.SIGN_BASE_URL``` would never be ```''```, yet could be ```'-2'``` while ```secrets.SIGN_BASE_URL``` was undefined.
2026-01-10 15:29:59 +08:00
fufesou
82fcab26b1 refact(sign): skip signed files (#14006)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-01-10 02:01:32 +08:00
fufesou
f3bbcc4f55 refact(sign): skip signed files (#14005)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-01-10 00:55:00 +08:00
21pages
98362eaca0 add Changelog link in update help card (#13997)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-01-09 15:34:51 +08:00
fufesou
998b75856d feat: Add relative mouse mode (#13928)
* feat: Add relative mouse mode

- Add "Relative Mouse Mode" toggle in desktop toolbar and bind to InputModel
- Implement relative mouse movement path: Flutter pointer deltas -> `type: move_relative` -> new `MOUSE_TYPE_MOVE_RELATIVE` in Rust
- In server input service, simulate relative movement via Enigo and keep latest cursor position in sync
- Track pointer-lock center in Flutter (local widget + screen coordinates) and re-center OS cursor after each relative move
- Update pointer-lock center on window move/resize/restore/maximize and when remote display geometry changes
- Hide local cursor when relative mouse mode is active (both Flutter cursor and OS cursor), restore on leave/disable
- On Windows, clip OS cursor to the window rect while in relative mode and release clip when leaving/turning off
- Implement platform helpers: `get_cursor_pos`, `set_cursor_pos`, `show_cursor`, `clip_cursor` (no-op clip/hide on Linux for now)
- Add keyboard shortcut Ctrl+Alt+Shift+M to toggle relative mode (enabled by default, works on all platforms)
- Remove `enable-relative-mouse-shortcut` config option - shortcut is now always available when keyboard permission is granted
- Handle window blur/focus/minimize events to properly release/restore cursor constraints
- Add MOUSE_TYPE_MASK constant and unit tests for mouse event constants

Note: Relative mouse mode state is NOT persisted to config (session-only).
Note: On Linux, show_cursor and clip_cursor are no-ops; cursor hiding is handled by Flutter side.

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

* feat(mouse): relative mouse mode, exit hint

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

* refact(relative mouse): shortcut

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-01-09 10:03:14 +08:00
21pages
3a9084006f Allow configuring remote control permissions for different users (#13974)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-01-09 00:21:28 +08:00
fufesou
4d3ccc62e8 fix(file transfer): perm on "access-mode" (#13971)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-01-07 16:08:15 +08:00
fufesou
8fe10d61ea fix(terminal): linux, macOS, win as the controlled (#13930)
1. `TERM` on linux terminal.
2. `htop` command not found on macOS.
3. `vim` and `claude code cli` hung up on windows.

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-01-07 16:07:14 +08:00
21pages
5a183490dc fix submodule repository (#13975)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-01-07 14:11:20 +08:00
21pages
9dd4fa8646 add options: disable-change-permanent-password, disable-change-id, disable-unlock-pin (#13929)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-01-07 13:51:02 +08:00
Yero~
a05b619563 Fix: Window positioning out of bounds on multi-monitors setup #13828 (#13903) 2026-01-07 13:50:26 +08:00
Alex Rijckaert
7f9506b476 Update Dutch (#13970) 2026-01-06 18:15:54 +08:00
21pages
f65952cf1c fix(desktop): wakelock issue with multiple tabs in same window (#13956)
Each desktop isolate now independently tracks wakelock state.
  WakelockPlus.disable() is only called when all tabs within the
  same isolate are closed/minimized.

  WakelockPlus ensures screen stays awake as long as any isolate
  has wakelock enabled.

Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-01-05 22:16:35 +08:00
Re*Index. (ot_inc)
7ac03ffefc Update Japanese translations in ja.rs (#13952) 2026-01-03 12:36:25 +08:00
bilimiyorum
f6d6c3afb5 Turkish language support (#13941)
New string entry
2026-01-02 22:13:32 +08:00
Alex Rijckaert
419703d2ea Update dutch translation for 'Show terminal extra keys' (#13939) 2026-01-02 22:11:18 +08:00
21pages
9301edef06 remove gzip encoding in Legacy AB pushes (#13937)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-01-02 10:24:47 +08:00
21pages
7e3f0a607b fix: add Content-Length header for empty body POST requests (#13940)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-01-02 09:14:31 +08:00
dependabot[bot]
dec0e7c56d Git submodule: Bump libs/hbb_common from fa15710 to 12f2a47 (#13923)
Bumps [libs/hbb_common](https://github.com/rustdesk/hbb_common) from `fa15710` to `12f2a47`.
- [Release notes](https://github.com/rustdesk/hbb_common/releases)
- [Commits](fa157108be...12f2a47770)

---
updated-dependencies:
- dependency-name: libs/hbb_common
  dependency-version: 12f2a47770af7521588ccaa67731806f15d0132d
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-31 13:28:45 +08:00
Lynilia
0758e10ae2 Update fr.rs (#13921) 2025-12-31 13:28:16 +08:00
Mr-Update
19ae785fa2 Update de.rs (#13919) 2025-12-31 13:28:04 +08:00
Kratos
918ce865ca Update hu.rs (#13918)
Translate new string
2025-12-31 13:27:53 +08:00
solokot
d27a21feee Update ru.rs (#13917) 2025-12-31 13:27:40 +08:00
VenusGirl❤
d8932b69a3 Update Korean (#13916) 2025-12-31 13:27:28 +08:00
bovirus
5af580f44d Italian language update (#13913) 2025-12-31 13:27:16 +08:00
alonginwind
3384eda8b7 feat(terminal): add two-row floating keyboard buttons for common commands (mobile only) (#13876)
* feat(terminal): add two-row floating keyboard buttons for common commands (mobile only)

* Fix missing newline at end of pl.rs

Add missing newline at the end of the file.
2025-12-28 15:41:25 +08:00
fufesou
969ea28d06 feat(fs): delegate win --server file reading to CM (#13736)
- Route Windows server-to-client file reads through CM instead of the connection layer
- Add FS IPC commands (ReadFile, CancelRead, SendConfirmForRead, ReadAllFiles) and CM data messages
  (ReadJobInitResult, FileBlockFromCM, FileReadDone, FileReadError, FileDigestFromCM, AllFilesResult)
- Track pending read validations and read jobs to coordinate CM-driven file transfers and clean them up
  on completion, cancellation, and errors
- Enforce a configurable file-transfer-max-files limit for ReadAllFiles and add stronger file name/path
  validation on the CM side
- Improve Flutter file transfer UX and robustness:
  - Use explicit percent/percentText progress fields
  - Derive speed and cancel actions from the active job
  - Handle job errors via FileModel.handleJobError and complete pending recursive tasks on failure
  - Wrap recursive directory operations in try/catch and await sendRemoveEmptyDir when removing empty directories

Signed-off-by: fufesou <linlong1266@gmail.com>
2025-12-28 15:39:35 +08:00
fufesou
5b2101e17d fix(terminal): macos, env TERM (#13901)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-12-26 15:28:35 +08:00
Andrzej Rudnik
ec2d7f0519 Update pl.rs (#13893) 2025-12-26 13:31:49 +08:00
fufesou
656ce93d6e refact: ci, free disk space(Ubuntu) (#13900)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-12-25 17:10:49 +08:00
RustDesk
b69e871f9a Revert "fix: set TERM env variable for terminal to fix Delete key not working…" (#13894)
This reverts commit bba57069a8.
2025-12-24 22:59:13 +08:00
lif
bba57069a8 fix: set TERM env variable for terminal to fix Delete key not working (#13747)
Set TERM=xterm-256color when spawning PTY shell to ensure proper
handling of control sequences. This fixes the issue where Delete/
Backspace keys were not working in terminal connections, particularly
from iPad to Linux.

Fixes #13621
2025-12-24 18:18:51 +08:00
fufesou
6a701f1420 fix: linux, home (#13879)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-12-23 15:43:31 +08:00
alonginwind
eba847e62e Fix Terminal top content overlapping with notch (SafeArea) (#13724) 2025-12-22 21:08:38 +08:00
fufesou
b80eb2dc6c refact: remote toolbar icon (#13865)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-12-22 17:10:53 +08:00
21pages
1f9689dc00 show login dialog when clicking note if not logged in (#13856)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-12-21 22:18:18 +08:00
YuZhiYuanDev
84eb75d5b6 ci: update macOS runner from unsupported macos-13 to macos-latest (#13855)
- Replace deprecated `macos-13` with `macos-latest` runner
- Ensure CI compatibility with supported macOS versions
- Maintain build stability and future-proof workflows
2025-12-20 21:21:14 +08:00
21pages
4f2aea65ab require login for note (#13775)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-12-20 16:51:25 +08:00
fufesou
d6463f95b9 refact: remote toolbar show/hide (#13843)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-12-19 20:45:22 +08:00
mehdi-song
3e0688ab63 Update fa.rs (#13818)
* Update fa.rs

:-)

* Update fa.rs
2025-12-17 22:32:16 +08:00
RustDesk
692e90f779 Update flutter-build.yml (#13817) 2025-12-16 10:33:50 +08:00
RustDesk
e4faedcb62 Update flutter-build.yml (#13815) 2025-12-15 19:51:48 +08:00
fufesou
a32d36a97b fix(sudo -E): Ubuntu 25.10, run_as_user (#13796)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-12-14 20:52:10 +08:00
RustDesk
da2c678fb3 Revert "Disable signing commands in flutter-build.yml (#13750)" (#13808)
This reverts commit 822b6d1baf.
2025-12-14 17:41:18 +08:00
Mahdi Rahimi
7bdfa121f3 Update Arabic translation in ar.rs (#13738) 2025-12-12 21:37:15 +08:00
fufesou
b9a1369c6f fix: custom client, contains RustDesk (#13783)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-12-11 21:17:42 +08:00
fufesou
0112b3387e fix(CI): macOS, nasm, use 2.16.x (#13781)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-12-11 20:16:06 +08:00
fufesou
de9d86621d fix: macos, clipboard, text-based items (#13778)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-12-11 15:39:18 +08:00
YuZhiYuanDev
735862d1fd Replace unsupported macos-13 with a new runner (#13767) 2025-12-10 17:05:52 +08:00
rustdesk
a0537759b1 fix vi 2025-12-10 00:31:13 +08:00
minh
a79776c1c4 Update Vietnamese translations for various terms (#13756) 2025-12-09 16:58:34 +08:00
RustDesk
822b6d1baf Disable signing commands in flutter-build.yml (#13750)
Comment out signing commands in the Flutter build workflow.
2025-12-09 00:07:11 +08:00
fufesou
0065085ba2 fix: win, peer shortcut, colon to underscore (#13740)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-12-08 16:34:05 +08:00
rustdesk
4f4da20fc0 revert: flatpak command line is_root 2025-12-05 17:26:06 +08:00
rustdesk
eb0174ea53 flatpak command line is_root 2025-12-05 17:15:29 +08:00
Vasyl Gello
20ce626654 Fix OpenSSL build with Android NDK clang on x86 (#13684)
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2025-12-04 17:54:07 +08:00
Alex Rijckaert
a342941ec1 Update Dutch translations for input notes (#13713) 2025-12-04 00:27:05 +08:00
21pages
a78a803a22 fix is_public (#13701)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-12-02 14:54:56 +08:00
fufesou
23754630e8 fix build (#13686)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-12-01 19:41:55 +08:00
bilimiyorum
8e6e91eb4a Turkish language support (#13673)
Current
2025-11-30 19:52:40 +08:00
fufesou
9cfa551163 fix: msi, prevent black window (#13665)
For msi version, the black window is shown when creating desktop
shortcut for connection.

The exe version does not have this issue.

Signed-off-by: fufesou <linlong1266@gmail.com>
2025-11-28 17:25:43 +08:00
rustdesk
5b21441898 webrtc 2025-11-28 10:45:48 +08:00
fufesou
4ed8696d1d fix: file transfer, jobs lost if conn is not established (#13635)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-11-26 19:15:32 +08:00
fufesou
ae06f27372 fix: sciter, cursor position mismatch (#13629)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-11-25 23:05:31 +08:00
XLion
33e1493932 Update tw.rs; Add space for cn.rs (#13609)
* Update tw.rs

* Update cn.rs

* Update tw.rs

* Update tw.rs
2025-11-25 01:08:48 +08:00
summoner
22b1dcaf7b Translation: Update hungarian hu.rs (#13578)
* Translation: Update hungarian hu.rs

Translate new strings
Fix translation

* Translation: update hu.rs

Fix translation

* Update hu.rs

Fix translation
2025-11-22 15:16:02 +08:00
fufesou
426a68775f feat: macos, update dmg (#13579) 2025-11-21 10:27:37 +08:00
RustDesk
3c0be4e40e Revert "feat: macos, update dmg (#13539)" (#13577)
This reverts commit a6571e71e4.
2025-11-20 23:18:00 +08:00
21pages
3787b45b49 fix python scripts read offset (#13574)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-11-20 22:15:42 +08:00
rustdesk
7d06de00fb 24.04 ubuntu24.04 ubuntu24.04 ubuntu24.04 ubuntu24.04 ubuntu24.04
ubuntu24.04 ubuntu24.04 ubuntu24.04 ubuntu24.04 ubuntu24.04 ubuntu24.04
ubuntu24.04 ubuntu24.04 ubuntu24.04 ubuntu24.04 ubuntu24.04 ubuntu24.04
ubuntu24.04 ubuntu24.04 ubuntu
2025-11-19 11:39:37 +08:00
fufesou
6f8af9d114 refact: flatpak, socket x11, better compatibility (#13551)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-11-19 11:03:06 +08:00
fufesou
0a672f092a fix: flatpak, wayland, cursor image (#13544)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-11-18 23:32:40 +08:00
alonginwind
ef62f1db29 Fix terminal clear command to remove residual output (#13531)
* Fix terminal clear command to remove residual output

* Update flutter/lib/models/terminal_model.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update flutter/lib/desktop/pages/terminal_page.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix: Prevent "Build scheduled during frame" in terminal resize

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-18 23:31:54 +08:00
fufesou
7f804a0e45 refact: wayland, pipewire display offset cache to file (#13542)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-11-18 14:16:59 +08:00
fufesou
b2dff336ce fix: wayland controlled side, cursor misalignment (#13537)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-11-18 00:37:15 +08:00
fufesou
a6571e71e4 feat: macos, update dmg (#13539)
* feat: macos, update dmg

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

* Update src/platform/macos.rs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix: macos update, remove temp update dir

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

* refact: macos update, print

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-18 00:30:23 +08:00
rustdesk
81f711eb00 update lock 2025-11-17 23:09:29 +08:00
rustdesk
c8a8e06558 update common 2025-11-17 19:09:50 +08:00
rustdesk
2c079f53a9 web client custom 2025-11-17 00:30:38 +08:00
Lynilia
322ffe288e Update fr.rs (#13533) 2025-11-16 23:47:25 +08:00
Mr-Update
c340eb0e57 Update de.rs (#13529) 2025-11-15 21:07:09 +08:00
rustdesk
4e953291ed fix ci android failure 2025-11-15 15:00:29 +08:00
solokot
1dea5fee0e Update ru.rs (#13518) 2025-11-14 17:02:33 +08:00
VenusGirl❤
9f24b46fee Update Korean (#13516) 2025-11-14 17:02:21 +08:00
bovirus
0808c41a1c Italian language update (#13513) 2025-11-14 17:02:09 +08:00
21pages
296c6df462 ask for note at end of connection (#13499)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-11-13 23:35:40 +08:00
Dzung Do
13ee3e907d Update Vietnamese translations for various terms (#13490) 2025-11-12 16:26:17 +08:00
Jonathan Gilbert
ce7d794b4c Fix config sync reconnection retry loop (#13487)
* Updated the server connection retry loop when syncing config changes in src/server.rs to not break after reconnecting.

* Update server.rs

---------

Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2025-11-12 00:27:58 +08:00
Alireza Shahamiri
fb10069632 fix(fa.rs): Fixes persian translation typo (#13459) 2025-11-11 14:45:38 +08:00
21pages
43a7677644 add user_group.py, device_group.py, update users.py (#13453)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-11-11 14:45:04 +08:00
fufesou
58fa32d7ea fix: sciter ui (#13474)
Element has no method - is_outgoing_only.

Signed-off-by: fufesou <linlong1266@gmail.com>
2025-11-10 22:30:20 +08:00
fufesou
934d6c3987 refact: rust backtrace logs (#13467)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-11-10 15:43:46 +08:00
rustdesk
2d7c6ef21f log crash traceback, copilot 2025-11-10 10:01:15 +08:00
Alex Rijckaert
99a97e6a6c Update Dutch translations in nl.rs (#13457) 2025-11-09 21:30:48 +08:00
rustdesk
017a10e8c8 1.4.4 2025-11-07 15:16:59 +08:00
Mr-Update
41ffa8ba08 Update de.rs (#13448) 2025-11-07 15:15:38 +08:00
21pages
e029d00cfa edge scroll thickness adjustment (#13445)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-11-07 01:15:13 +08:00
Lynilia
268534d5e7 Update fr.rs (#13438) 2025-11-06 17:13:27 +08:00
fufesou
a7d2bc63f9 fix: sciter, advanced options, UI (#13429)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-11-06 17:13:11 +08:00
bovirus
559115c43c Italian language update (#13414)
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2025-11-05 17:53:35 +08:00
Greg
1277c7d60c See https://github.com/rustdesk/rustdesk/discussions/13350 (#13427)
This adds DBUS_SESSION_BUS_ADDRESS to the collection of "pilfered environment" variables on Linux.

The net effect should be that Wayland sub processes launched by rustdesk --service (--server and --tray) get the right bus.

Presumably this happens with by systemd environment management, but on Void Linux & other non-systemd, this prevents a connection to a client from any controller with a message about service not available. (As the DBUS lookup fails).

On X11, this is not an issue as the retrieval of Wayland capabilities via DBUS registry is not required.

In general, this is a more robust Wayland solution than just grabbing WAYLAND_DISPLAY, since WAYLAND is heavily dependent on DBUS for protocol registration.

Co-authored-by: Greg Ke <Greg-repo-sync@akua.com>
2025-11-05 10:29:37 +08:00
fufesou
9b69c7e972 refact: show proxy settings on ios (#13423)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-11-04 17:55:04 +08:00
Jonathan Gilbert
a903f710ea Eliminate build warnings from the Scrap crate (#13383)
* Updated build.rs to tell RustC that dxgi, quartz and x11 are expected configurations.
Added lifetime annotations to various methods in common/aom.rs and common/vpxcodec.rs.
Updated common/vpx.rs to allow unused_imports in the generated bindings.
Updated dxgi/mag.rs to allow non_snake_case identifiers like "dwFilterMode".

* Added lifetime annotations to methods in common/hwcodec.rs and common/vram.rs.

* Switched syntax for the rustc-check-cfg directive emitted by build.rs in the scrap crate to use syntax compatible with Rust toolchain version 1.75. The double-colon syntax requires 1.77 or newer, but the older single-colon syntax works fine on newer versions for this directive.

* Update libs/scrap/build.rs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Revert apparently-erroneous AI suggestion. It's usually pretty good, but not always right it seems. :-)

This reverts commit bf862b13f6.

* Removed redundant configuration directives from libs/scrap/build.rs.

---------

Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-04 10:19:13 +08:00
21pages
b75f4daa47 flutter: keep chat window within screen bounds to prevent hidden chat window (fixes rustdesk#13397) (#13406) 2025-11-04 09:44:13 +08:00
fufesou
fef44ffa57 refact: translate tip id (#13412)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-11-04 08:56:43 +08:00
fufesou
5a812e3b2f fix: ui issues (#13381)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-11-03 23:23:08 +08:00
fufesou
910dcf2036 refact: tls, native-tls fallback rustls-tls (#13263)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-11-03 23:21:01 +08:00
21pages
44a28aa5bd update hwcodec, support H265 encoding on Intel chip Macs (#13411)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-11-03 22:55:03 +08:00
21pages
f7f947beb9 restrict CLI options when settings disabled (#13400)
Prevent --password, --set-id, and --option command line arguments
from modifying settings when is_disable_settings() returns true.

Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-11-03 09:43:27 +08:00
RustDesk
d03a9e2baf Fix macos bigsur cvbuffer crash (#13392)
* Fix macOS Big Sur crash with CVBufferCopyAttachments

Add FFmpeg patch to use weak_import for CVBufferCopyAttachments API
to prevent dyld crash on macOS Big Sur (11.x).

The CVBufferCopyAttachments function is only available on macOS 12+.
Even though FFmpeg has a runtime check with __builtin_available, the
symbol is still resolved at load time, causing immediate crash on older
macOS versions.

With weak_import attribute, the function pointer will be NULL on
macOS < 12, allowing the code to safely fall back to the deprecated
CVBufferGetAttachments API.

Fixes: #13377

* update common
2025-11-02 22:08:03 +08:00
Mr-Update
ca22316e95 Update de.rs (#13375) 2025-11-02 21:20:56 +08:00
solokot
ef99c479aa Update ru.rs (#13367) 2025-11-02 21:20:42 +08:00
Jonathan Gilbert
fa9260c763 Made the import of hbb_common::sysinfo::System more precisely conditioned in src/platform/mod.rs. (#13388) 2025-11-02 21:19:44 +08:00
Jonathan Gilbert
fab11c8ffa Allow non_snake_case identifiers in src/setup/mod.rs for libs/remote_printer. (#13384) 2025-11-02 21:19:13 +08:00
VenusGirl❤
9bd9658a92 Update Korean (#13359)
Update Korean
2025-11-01 14:40:28 +08:00
bovirus
213880c14d Italian language update (#13358) 2025-11-01 14:40:17 +08:00
Alessandro De Blasis
0550397046 fix: scale custom on mobile (#13324)
* fix: prevent custom scale dialog from closing when interacting with slider

Wrapped MobileCustomScaleControls in GestureDetector with opaque behavior
to prevent touch events from propagating to parent dialog's clickMaskDismiss
handler. The slider now works correctly without closing the dialog.

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* Update flutter/lib/mobile/widgets/custom_scale_widget.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update flutter/lib/mobile/widgets/custom_scale_widget.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update flutter/lib/mobile/widgets/custom_scale_widget.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update flutter/lib/mobile/widgets/custom_scale_widget.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Revert "fix: mobile remove "Scale custom" (#13323)"

This reverts commit 265d08fc3b.

* chore: keep remote_toolbar.dart cleanup (remove dead code)

  The dead code removed in 265d08fc3 hasn't been used since Aug 2023.
  Only reverting toolbar.dart is needed for the mobile Scale custom fix.

* Update flutter/lib/mobile/pages/remote_page.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor: Implement CustomScaleControlsMixin for shared scaling logic across mobile and desktop widgets

- Introduced a new mixin `CustomScaleControlsMixin` to encapsulate custom scale control logic, allowing for code reuse in both mobile and desktop widgets.
- Refactored `_CustomScaleMenuControlsState` and `_MobileCustomScaleControlsState` to utilize the new mixin, simplifying the scaling logic and reducing code duplication.
- Updated slider handling and state management to leverage the mixin's methods for improved maintainability.

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* Update flutter/lib/desktop/widgets/remote_toolbar.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update flutter/lib/mobile/widgets/custom_scale_widget.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update flutter/lib/mobile/pages/remote_page.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor: changed from mixin to abstract class

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* Revert "Update flutter/lib/mobile/pages/remote_page.dart"

This reverts commit 7c35897408.

* refactor: remove unnecessary tap event handling in custom scale controls

- Removed the `onTap` handler from the

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* refactor: simplify MobileCustomScaleControls usage in remote_page.dart

- Removed unnecessary GestureDetector wrapper around MobileCustomScaleControls for cleaner code.

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

---------

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-31 11:08:03 +08:00
21pages
f7a5a506f6 rename RustDeskApplication to MainApplication (#13362)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-10-31 11:07:32 +08:00
21pages
0f34c50bd2 fix reqwest proxy auth (#13354)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-10-30 20:01:17 +08:00
Jonathan Gilbert
055826e26f Edge scrolling (#13247)
* Repurposed the MacOS-specific platform channel mechanism for all platforms:
- Renamed the channel from "org.rustdesk.rustdesk/macos" to "org.rustdesk.rustdesk/host".
- Renamed _osxMethodChannel in platform_channel.dart to _hostMethodChannel.
- Updated linux/my_application.cc to use the fl_* API to set up a Method Channel and to dispose it during my_application_dispose.
- Updated windows/runner/flutter_window.cpp to use the C++ API to set up a Method Channel.
- Updated the channel name in macos/Runner/MainFlutterWindow.swift.

Signed-off-by: Jonathan Gilbert <logic@deltaq.org>

* Added a method "bumpMouse" to the Platform Channel.
Added a thunk to call the method through the channel to platform_channel.dart.
Added implementation bump_mouse() in linux/my_application.cc using Gdk API calls. Updated host_channel_call_handler to process "bumpMouse" method call messages by calling bump_mouse.
Added implementation Win32Desktop::BumpMouse in windows/runner/win32_desktop.cpp/.h.  Updated the inline method call handler in flutter_window.cpp to handle "bumpMouse" method calls by calling Win32Desktop::BumpMouse.
Updated the method call handler in macos/Runner/MainFlutterWindow.swift to handle "bumpMouse" method call messages. Updated MainFlutterWindow to use a subclass of FlutterViewController exposing access to mouseLocationOutsideOfEventStream.

Signed-off-by: Jonathan Gilbert <logic@deltaq.org>

* Added message type kWindowBumpMouse to the multiwindow window event model:
- Added constant kWindowBumpMouse to consts.dart.
- Updated the method handler attached to rustDeskWinManager by DesktopHomePageState to recognize kWindowBumpMouse and translate it to a call to RdPlatformChannel.bumpMouse.

Signed-off-by: Jonathan Gilbert <logic@deltaq.org>

* Centralized serialization of ScrollStyle values, moving JSON and string conversions into methods toString/fromString and toJson/fromJson within the type.

Signed-off-by: Jonathan Gilbert <logic@deltaq.org>

* Added new scroll style for edge scrolling:
- Added ScrollStyle enum member "scrolledge". Added corresponding constant kRemoteScrollStyleEdge to consts.dart for the string serialized form.
- Updated sites checking specifically for ScrollStyle.scrollbar to instead check for NOT ScrollStyle.scrollauto.
- Added radio buttons for the new "ScrollEdge" style to desktop_setting_page.dart and remote_toolbar.dart. Added new string "ScrollEdge" to lang/template.rs.

Signed-off-by: Jonathan Gilbert <logic@deltaq.org>

* Implemented edge scrolling:
- Added methods edgeScrollMouse and pushScrollPositionToUI to class CanvasModel in model.dart.
- Added boolean parameter edgeScroll to handleMouse, handlePointerDevicePos and processEventToPeer in input_model.dart.
- Updated handlePointerDevicePos in input_model.dart to call edgeScrollMouse on move events when the edgeScroll parameter is true.
- Added convenience accessor useEdgeScroll to the InputModel class. Updated call sites to handleMouse to use it to supply the value for the edgeScroll parameter.

Signed-off-by: Jonathan Gilbert <logic@deltaq.org>

* Updated CanvasModel.edgeScrollMouse to be resilient to receiving events when _horizontal/_vertical aren't wired up to any UI.

* Updated CanvasModel to take notifications of resizes via method notifyResize and to suppress edge scrolling briefly after a resize.
Updated the onWindowResized handler in tabbar_widget.dart to call notifyResize on the canvasModel of any RemotePage tabs.

* Half a go at fixing MainFlutterWindow.swift.

* Copilot feedback.

* Applied fix suggested by Copilot in its explanation of the build error.

* Fixed a couple of silly errors in windows/runner/flutter_window.cpp.

* Fixed MainFlutterWindow.swift build errors.

Co-Authored-By: fufesou <linlong1266@gmail.com>
Signed-off-by: Jonathan Gilbert <logic@deltaq.org>

* Moved new translation to the end of template.rs.
Reran res/lang.py.

Signed-off-by: Jonathan Gilbert <logic@deltaq.org>

* Switched MainFlutterWindow.swift to use NSEvent.mouseLocation.

* Updated MainFlutterWindow.swift code based on build error.

* Fixed silly typo.

* Reintroduced the coordinate system translation in MainFlutterWindow.swift.

* Updated edgeScrollMouse in model.dart to add a "safe zone" around the window frame that doesn't trigger edge scrolling.

* Updated the bumpMouse handler in MainFlutterWindow.swift to call CGAssociateMouseAndMouseCursorPosition to cancel event suppression.

* Added debug annotation to the onWindowResized event in tabbar_widget.dart.

* Fix parameter type for CGAssociateMouseAndMouseCursorPosition in MainFlutterWindow.swift.

* tabbar_widget.dart: onWindowResized -> onWindowResize

* Removed temporary diagnostic debugPrint from tabbar_widget.dart.

* Updated MainFlutterWindow.swift to obtain the mouse position by creating a dummy CGEvent. The old NSEvent.mouseLocation code is left as a fallback.

* The documentation said to be sure to call CFRelease, but apparently it's a build error to do so. :-P

* Replaced CGEvent calls in MainFlutterWindow.swift with uses of the CGEvent wrapper struct.

* Added argument label to call to CGEvent.init.

* Changed mouseLoc from piecewise assignment to assignment of the whole structure, as it is not yet initialized at that point.

* Linux platform channel: Refactored bump_mouse, setting the stage for a future Wayland implementation.
- Made a new top-level bump_mouse method in bump_mouse.cc/.h.
- Moved the X11-specific implementation to bump_mouse_x11 in bump_mouse_x11.cc/h.
Reworked the bumpMouse operation to have a boolean return value:
- Updated bumpMouse in platform_channel.dart to return a Future<bool> instead of a Future<void>.
- Windows platform channel: Updated BumpMouse in win32_desktop.cpp to return a bool value. Updated the method call handler "bumpMouse" branch in flutter_window.cpp to propagate the BumpMouse return value back to the originating MethodCall.
- MacOS platform channel: Updated the "bumpMouse" branch in the method call handler in MainFlutterWindow.swift to pass true or false into the 'result()' call.
- Linux platform channel: Updated the bump_mouse top-level method and its underlying implementation bump_mouse_x11 to return bool values. Updated the "bumpMouse" branch of host_channel_call_handler in my_application.cc to propagate the result value back up the method channel.
- Updated the kWindowBumpMouse branch of the method handler registered in desktop_home_page.dart to propagate a return value from RdplatformChannel.bumpMouse.

* Reworked the edge scrolling computations in model.dart to use Vector2 from the vector_math package. Updated pubspec.yaml to declare a dependency on vector_math.

* Added an alternative edge scrolling mechanism for when "Bump Mouse" functionality is unavailable:
- Added methods setEdgeScrollTimer and cancelEdgeScrollTimer to model.dart, along with a few state fields.
- Updated edgeScrollMouse to latch the (x, y) coordinate of the last edge scroll event, in case it will be autorepeating.
- Updated edgeScrollMouse to check whether the call to the kWindowBumpMouse method of rustDeskWinManager (and thus the underlying bump_mouse method) succeeded, and to switch to timer-based autorepeat if it fails. Made edgeScrollMouse async to allow awaiting the result of the kWindowBumpMouse method call.
- Updated input_model.dart to call cancelEdgeScrollTimer when a new move event is being processed.
- Updated remote_page.dart to call cancelEdgeScrollTimer when the pointer exits the area represented by the view.

* Fixed scroll percentage math in edgeScrollMouse in model.dart.

* Fixed declared return value for Win32Desktop::BumpMouse in win32_desktop.h.

* Fixed vector_math dependency version in pubspec.yaml to be compatible with the codebase standard Flutter version.

* Added class EdgeScrollFallbackState to model.dart for tracking the state of the edge scroll fallback strategy. Factored out the actual edge scrolling action from CanvasModel.edgeScrollMouse to new method performEdgeScroll so that EdgeScrollFallbackState can call it. Updated edgeScrollMouse to not call performEdgeScroll when it's enabling the fallback strategy.
Updated CanvasModel to use EdgeScrollFallbackState instead of directly tracking the state. Removed method setEdgeScrollTimer.
Added method initializeEdgeScrollFallback to CanvasModel that takes a TickerProvider. Updated _RemotePageState to include the mixin TickerProviderStateMixin. Updated _RemotePageState.initState to call canvasModel.initializeEdgeScrollFallback.
Updated handlePointerDevicePos in input_model.dart to not call cancelEdgeScrollTimer before edgeScrollMouse.
Renamed CanvasModel.cancelEdgeScrollTimer to CanvasModel.cancelEdgeScroll.
Updated the calculations in CanvasModel.edgeScrollMouse to only factor in the safe zone if BumpMouse is working. (Otherwise the problem with resizing can't possibly occur.)

* Updated CanvasModel.edgeScrollMouse in model.dart to handle the situation where only one of the scrollbars is active. Factored extraction of scrollbar data into new function getScrollInfo.

* Updated onWindowResize in tabbar_widget.dart to be resilient to RemotePage instances that don't yet have an ffi reference. Added property hasFFI to remote_page.dart.

* Removed debug output from model.dart.

* PR feedback:
- Added filtering to diagnostic output in the method handler in desktop_home_page.dart to exclude the very chatty kWindowBumpMouse-related output.
- Removed the diagnostic output from bumpMouse in platform_channel.dart for the same reason.
- Updated setScrollPercent to coalesce NaN values for x and y to 0.
- Initialized the GError pointer variable passed into fl_method_call_respond_success in linux/my_application.cc to NULL.
- Added bounds checking of the argument values in the EncodableList branch of the "bumpMouse" method call handler in windows/runner/flutter_window.cpp.

* Added a latch mechanism that keeps edge scrolling disabled until the cursor is observed to be in the inner area bounded by the edge scroll areas:
- Added tristate enumerated type EdgeScrollState to model.dart. In addition to inactive and active states, there is state armed which behaves like inactive but can transition to active when conditions are met.
- Added a field to CanvasModel of type EdgeScrollState. Added methods disableEdgeScroll and rearmEdgeScroll.
- Updated enterView to call canvasModel.rearmEdgeScroll and leaveView to call canvasModel.disableEdgeScroll in remote_page.dart.
- Updated edgeScrollMouse to check the state, disabling edge scrolling when the state is not active and transitioning from armed to active when the mouse is in the interior space.
- Removed the notifyResize/_suppressEdgeScroll mechanism from CanvasModel in model.dart as it is no longer necessary.
- Removed the "safe zone" mechanism from CanvasModel.edgeScrollMouse in model.dart as it is no longer necessary.
- Switched the onWindowResize handler in DesktopTabState in tabbar_widget.dart back to onWindowResized, now that it is no longer delivering canvasModel.notifyResize to all RemotePage tabs.

* Fixed memory leak: Added call to free GError object returned by Flutter API in the event of an error.

* PR feedback:
- Copilot: Use type annotations.
- Copilot: Condition to stop edge scrolling when fallback strategy is in use and the mouse is moved back to the centre.
- Copilot: Check FLValue type before calling fl_value_get_int.
- Copilot: Support list-style method channel dispatch in "bumpMouse" handler for macos as the linux and windows implementations already do.
- Naming convention for constants.
- Left-over variable from previous strategy: _suppressEdgeScroll.
- Unnecessary extra parentheses in edge scroll area conditions.

* Removed property suppressEdgeScroll referencing now-removed field _suppressEdgeScroll in model.dart.
Removed accidental extra blank line in MainFlutterWindow.swift.

* Switched CanvasModel.setScrollPercent to use double.isFinite instead of double.isNaN to test for proper numerical values.

* PR feedback:
- Copilot: Use Vector2.length2 instead of Vector2.length to avoid an unnecessary sqrt in comparison with zero.
- Copilot: Baleet unnecessary semicolons from Swift code.

* PR feedback:
- Copilot: Check argList.count before indexing it

* Oops with the semicolons again.

* Edge scroll, active local cursor

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

* Remove duplicated condition checks

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

* Chore

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

* PR feedback:
- Copilot: Removed unused property hasFFI from remote_page.dart.
- Copilot: Updated updateScrollStyle in model.dart to be resilient to the possibility of bind.sessionGetScrollStyle returning null.

* Factored local cursor updates out of CanvasModel.moveDesktopMouse in model.dart, adding new methods activateLocalCursor and updateLocalCursor.
Updated handlePointerDevicePos in input_model.dart to call canvasModel.updateLocalCursor on every mouse event.
Updated initState in remote_page.dart to schedule a call to canvasModel.activateLocalCursor as a first-image callback.

* Updated the explanation for rounding away from 0 in edgeScrollMouse in model.dart.

---------

Signed-off-by: Jonathan Gilbert <logic@deltaq.org>
Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: fufesou <linlong1266@gmail.com>
2025-10-30 19:54:11 +08:00
flusheDData
a30582c840 New Spanish transtion terms (#13344)
* Update es.rs

New terms added

* Update es.rs

New terms added
2025-10-30 15:34:56 +08:00
21pages
d106d97b99 mobile verify both webpki and installed CA (#13272)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-10-30 13:59:00 +08:00
alonginwind
d4410e78e2 feat(ui): show alias instead of peerId in terminal tab label (#13332) 2025-10-29 16:11:20 +08:00
fufesou
e3fcc6cce3 fix: file transfer, auto start on reconnect (#13329)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-10-29 15:15:05 +08:00
fufesou
265d08fc3b fix: mobile remove "Scale custom" (#13323)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-10-28 20:25:33 +08:00
21pages
7c8329c5c6 fix mac hwcodec check (#13320)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-10-28 16:29:42 +08:00
Kendall
d3947c9a19 Fix typo in Spanish translation for downloading message (#13289) 2025-10-27 17:09:42 +08:00
Luca-rickrolled-himself
cd99331668 Add Romanian Locale (#13270)
* Create CODE_OF_CONDUCT-RO.md

* Create CONTRIBUTING-RO.md

* Create SECURITY-RO.md

* Create README-RO.md

* Update README.md
2025-10-27 16:52:36 +08:00
Re*Index. (ot_inc)
472e18b10a Update Japanese (#13268) 2025-10-27 16:52:22 +08:00
Ivan Beà
d443f5de28 Update catalan translation ca.rs (#13267)
Update catalan translation
2025-10-27 16:52:10 +08:00
21pages
3242d132f6 opt ui of Windows session dialog (#13303)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-10-27 16:51:30 +08:00
Tomppaa
e66d2facd4 Create fi.rs (#13212)
Please add Finnish language rustdesk.
2025-10-26 21:28:56 +08:00
Tomppaa
f15b8dc0da Update lang.rs (#13259)
added finnish language.
2025-10-26 21:28:35 +08:00
Nguyễn Quý Hy
3275824aec Allow flipping sort order in mobile app's file transfer (#13273)
* Allow flipping sort order in mobile app's file transfer

Signed-off-by: Nguyen Quy Hy <nguyenquyhy@live.com.sg>

* Change ascending to be non-nullable

Signed-off-by: Nguyen Quy Hy <nguyenquyhy@live.com.sg>

* Revert file_model change

Signed-off-by: Nguyen Quy Hy <nguyenquyhy@live.com.sg>

---------

Signed-off-by: Nguyen Quy Hy <nguyenquyhy@live.com.sg>
2025-10-25 21:10:26 +08:00
21pages
965cb704ec add try catch on android setCodecInfo in case of unexpected crash (#13280)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-10-24 21:04:18 +08:00
fufesou
938e165470 fix: save frame, LateInitializationError (#13265)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-10-24 17:20:56 +08:00
esterTion
9058ef3344 ios: Enable file sharing and document browser support (#13226) 2025-10-23 15:58:50 +08:00
fufesou
ed39cc3038 fix: video service, wait timeout (#13208)
Use multiple frame fetched notifiers.

Signed-off-by: fufesou <linlong1266@gmail.com>
2025-10-22 13:19:08 +08:00
21pages
a77752c4cb fix tab lable translation (#13240)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-10-21 15:39:52 +08:00
21pages
c9940957f0 fix camera large error log (#13227)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-10-20 13:23:41 +08:00
Andrzej Rudnik
c90d72d720 Update pl.rs (#13210) 2025-10-19 14:19:53 +08:00
XLion
2c30bd9d24 Update tw.rs (#13203) 2025-10-18 16:39:08 +08:00
rustdesk
f2dc8e21a8 build 61 2025-10-18 08:50:07 +08:00
fufesou
6a0da9cf09 fix: custom scale, dpi (#13197)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-10-18 00:35:43 +08:00
rustdesk
d55974c352 --terminal command line 2025-10-17 19:22:46 +08:00
Gyuris Gellért
a898c22f4b Translation: Review and update hu.rs (#13169)
Some translation conventions, linguistic correctness, and spelling review.
2025-10-17 16:10:23 +08:00
solokot
b82e8bedfc Update ru.rs (#13168) 2025-10-17 16:09:55 +08:00
VenusGirl❤
7453cefd94 Update ko.rs (#13152)
Update Korean
2025-10-17 16:09:30 +08:00
Lynilia
1ed6b958cb Update fr.rs (#13151) 2025-10-17 16:09:16 +08:00
Alex Rijckaert
57896ab176 Update nl.rs (#13150) 2025-10-17 16:09:02 +08:00
Mr-Update
5c370b3914 Update de.rs (#13149)
* Update de.rs

* Update de.rs
2025-10-17 16:08:37 +08:00
rustdesk
182e35adc7 1.4.3 2025-10-17 13:58:08 +08:00
fufesou
d0a360fd80 refact: option, touch mode, move to local (#13055)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-10-17 13:36:46 +08:00
21pages
2fbc0625de fix macos low fps after installation (#13185)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-10-16 17:27:23 +08:00
fufesou
d3d20a4e20 fix: Wayland, cpu 100, workaround (#13179)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-10-15 21:59:48 +08:00
21pages
2c088d3504 fix can't run from cmd on win7 (#13160)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-10-14 12:11:05 +08:00
bovirus
6f9728f2d4 Italian language update (#13148) 2025-10-13 20:43:07 +08:00
21pages
30552fd202 show peer note (#13140)
Signed-off-by: 21pages <sunboeasy@gmail.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2025-10-12 14:59:42 +08:00
Mahdi Rahimi
9826c4e943 Update Arabic translation in ar.rs (#13144) 2025-10-12 14:55:51 +08:00
Mahdi Rahimi
bb9445bd0f Updated Persian translations in fa.rs (#13143) 2025-10-12 14:55:37 +08:00
Mr-Update
1f7e66f4cb Update de.rs (#13138) 2025-10-12 14:55:23 +08:00
bovirus
2a34e918a0 Italian language update (#13136) 2025-10-12 14:55:01 +08:00
VenusGirl❤
21c0d924ab Update ko.rs (#13134) 2025-10-12 14:54:40 +08:00
Lynilia
c8d5ee6565 Update fr.rs (#13132) 2025-10-12 14:51:37 +08:00
fufesou
3d8fc7ca7b fix: uninstall, idd (#13142)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-10-12 09:14:21 +08:00
Jonathan Gilbert
246b5b93f8 Centralize debounce of save window pos and save window pos on close (#12987)
* Added method equals to class LastWindowPosition to compare the contents of instances.
Added storage to common.dart for remembering what window position data has previously been written.
Factored the actual save code from saveWindowPosition to _saveWindowPositionActual and updated saveWindowPosition to call it through a debouncer, and only if the window position data has actually changed since the last call in the same instance.
Added named parameter 'flush' to saveWindowPosition in common.dart, and to _saveFrame in tabbar_widget.dart, and updated the onWindowClosed handler in tabbar_widget.dart to call _saveFrame with flush: true, forcing an immediate save on close.
Removed the _saveFrame debouncer from tabbar_widget.dart.

* saveWindowPosition: don't reschedule debounce if it's already in flight

* Reworked the logic in saveWindowPosition to collapse a rapid series of updates into one save at the end.
2025-10-11 16:11:56 +08:00
dependabot[bot]
2183c0980b Git submodule: Bump libs/hbb_common from 7ea8686 to 5ed0afd (#13122)
Bumps [libs/hbb_common](https://github.com/rustdesk/hbb_common) from `7ea8686` to `5ed0afd`.
- [Release notes](https://github.com/rustdesk/hbb_common/releases)
- [Commits](7ea868612d...5ed0afde08)

---
updated-dependencies:
- dependency-name: libs/hbb_common
  dependency-version: 5ed0afde0841659e2fb37ae7acaddc005fa1a8d3
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-10 17:44:59 +08:00
rustdesk
4ae301710d upload x86 windows 2025-10-10 00:23:48 +08:00
Re*Index. (ot_inc)
5f9390c210 Update Japanese Language (#13123) 2025-10-09 17:51:03 +08:00
fufesou
0f3a03aab7 feat: mobile, virtual mouse (#12911)
* feat: mobile, virtual mouse

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

* feat: mobile, virtual mouse, mouse mode

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

* refact: mobile, virtual mouse, mouse mode

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

* feat: mobile, virtual mouse mode

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

* feat: mobile virtual mouse, options

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2025-10-09 08:23:55 +08:00
summoner
02f455b0cc Translation: Update hu.rs (#13115)
Translate new strings
2025-10-09 08:21:44 +08:00
bovirus
ffddf60184 Update Italian language (#13117) 2025-10-09 08:21:30 +08:00
Alessandro De Blasis
482840b8bb feat(ui): custom scale mode with inline controls and live apply (#13045)
* feat(ui): custom scale mode with inline controls and live apply

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* Update flutter/lib/models/model.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update flutter/lib/desktop/widgets/remote_toolbar.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor(dialog): remove unused showCustomScaleDialog function

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* feat(ui): enhance custom scale controls with live updates and improved UI

- Introduced a reactive custom scale percentage using RxInt.
- Added initialization of custom scale from stored options after the widget builds.
- Updated viewStyle method to conditionally display custom controls based on selection.
- Implemented a debouncer for smoother scale adjustments.
- Enhanced slider UI with custom thumb shape and improved button interactions.

This update improves user experience by allowing real-time adjustments to the custom scale settings.

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* refactor(remote_toolbar): improve widget lifecycle management and enhance slider dimensions

- Moved initialization of custom scale percentage to initState for better lifecycle handling.
- Updated slider thumb dimensions and layout for improved UI consistency.
- Added dispose method to clean up resources in custom scale controls.

These changes enhance the overall performance and user experience of the remote toolbar.

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* feat(remote_toolbar): enhance scroll behavior and improve slider thumb rendering

- Introduced a new state variable to manage scroll enablement based on canvas model changes.
- Updated the return value of the viewStyle method to include the scroll enablement status.
- Refactored the slider thumb shape for better performance and visual consistency.
- Improved the initialization of image overflow detection in the CanvasModel.

These changes enhance the user experience by providing dynamic scroll control and a more responsive UI.

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* Update flutter/lib/desktop/widgets/remote_toolbar.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor(scale): introduce utility functions for custom scale management for DRY

- Added a new file `scale.dart` containing utility functions to clamp, parse, and compute custom scale percentages.
- Refactored the `CanvasModel` and `_DisplayMenuState` to utilize the new utility functions for fetching and applying custom scale settings.
- Improved code readability and maintainability by centralizing scale-related logic.

These changes enhance the handling of custom scale settings across the application.

Signed-off-by: Alessandro De Blasis alex@deblasis.net
Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* Update flutter/lib/utils/scale.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update flutter/lib/models/model.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update flutter/lib/desktop/widgets/remote_toolbar.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update flutter/lib/desktop/widgets/remote_toolbar.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update flutter/lib/desktop/widgets/remote_toolbar.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update flutter/lib/models/model.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* chore: Remove unused import of 'uuid' in scale.dart

Signed-off-by: Alessandro De Blasis alex@deblasis.net
Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* feat(remote_toolbar): implement nonlinear mapping for custom scale slider

- Added piecewise mapping functions to convert normalized slider positions to custom scale percentages and vice versa.
- Introduced snapping behavior for the slider to enhance user experience.
- Updated the slider's minimum and maximum values to align with the new mapping logic.
- Adjusted the clamping function to ensure the minimum percentage is 10.

These changes improve the precision and usability of the custom scale slider in the remote toolbar.

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* fix(scale): update minimum scale percentage to 5

- Adjusted the minimum scale percentage in both the remote toolbar and the clamping function to improve consistency and usability.
- This change aligns the clamping logic with the updated minimum value for the custom scale slider.

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* Update flutter/lib/desktop/widgets/remote_toolbar.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor(scale): centralize custom scale constants in consts.dart

- Moved piecewise mapping constants for the custom scale slider from the remote toolbar to consts.dart for better organization and maintainability.
- Introduced additional constants related to custom scale behavior, including minimum, pivot, and maximum percentages, as well as debounce duration.
- Updated the remote toolbar to reference these centralized constants, improving code clarity and reducing duplication.

These changes enhance the structure and readability of the custom scale implementation.

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* refactor(consts): remove duplicate custom scale percent key definition

- Eliminated redundant declaration of the custom scale percent key in consts.dart, ensuring a single source of truth for this constant.
- This change improves code clarity and maintainability by reducing duplication.

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* refactor(scale): update clamping logic to use centralized constants

- Modified the clamping function to utilize the newly defined constants for minimum and maximum scale percentages, enhancing code maintainability and clarity.
- This change ensures consistency across the application by referencing a single source for scale limits.

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* Enhance RdoMenuButton behavior for custom scale selection

- Updated the RdoMenuButton to include a new `closeOnActivate` parameter, allowing the submenu to remain open when selecting custom scale options.
- Modified the onChanged callback to conditionally trigger a rebuild when entering custom mode, improving user experience by immediately displaying the slider controls.

These changes streamline the interaction with the custom scale feature in the remote toolbar.

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* refactor(toolbar):  _DisplayMenuState to simplify scroll handling

- Removed the _scrollEnabled state variable and its associated logic, streamlining the component's state management.
- Updated the RdoMenuButton onChanged callbacks to directly reference the canvasModel's imageOverflow value, enhancing responsiveness and reducing complexity.

These changes improve code clarity and maintainability in the remote toolbar's display menu.

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* feat(lang): Add translations for custom scale features in multiple languages

- Introduced new entries for "Scale custom", "Custom scale slider", "Decrease", and "Increase" in various language files to support the custom scale functionality.
- This update enhances the localization of the application, ensuring users can interact with the custom scale features in their preferred language.

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* feat(lang): Add translations for custom scale features in Catalan and Romanian

- Updated language files for Catalan and Romanian to include translations for "Custom scale slider", "Decrease", and "Increase".
- This enhancement improves the localization of the application, allowing users to interact with custom scale features in their native languages.

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* fix(model): Correct error logging in getSessionCustomScale method

- Updated the error logging statement in the getSessionCustomScale method to properly interpolate the exception message, improving debugging clarity.
- This change ensures that error messages are more informative, aiding in troubleshooting issues related to session scaling.

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* refactor(scale): Simplify clamping logic for custom scale percent

- Updated the clampCustomScalePercent function to use the built-in clamp method, improving code readability and maintainability.
- This change ensures consistent clamping behavior across the application by centralizing the logic for valid scale ranges.

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* refactor(scale): Remove unused import for web bridge

- Eliminated the conditional import of the web bridge from scale.dart, as it is no longer necessary. This change helps to clean up the code and improve maintainability by removing unused dependencies.

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* chore(model): typo

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* Update flutter/lib/desktop/widgets/remote_toolbar.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* chore(toolbar): Clarify precision for scale adjustments in remote toolbar

- Added comments to clarify the use of a wide range of divisions for the scale slider, allowing for ~1% precision increments. This change improves user experience by enabling more precise scale value settings, reducing the need for fine-tuning with +/- buttons.

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* Update flutter/lib/models/model.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update flutter/lib/desktop/widgets/remote_toolbar.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix(model): Enhance error logging in getSessionCustomScale method

- Improved error logging by adding stack trace output to debugPrintStack, enhancing debugging capabilities for session scaling issues.
- This change provides clearer insights into errors encountered during scale retrieval, aiding in troubleshooting.

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* refactor(toolbar): Simplify custom scale percent retrieval in remote toolbar

- Replaced the previous method of retrieving the custom scale percent with a new function, getSessionCustomScalePercent, enhancing code clarity and maintainability.
- This change streamlines the process of obtaining the scale value, ensuring a more efficient and readable implementation.

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

* Update flutter/lib/desktop/widgets/remote_toolbar.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>
Signed-off-by: Alessandro De Blasis alex@deblasis.net
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2025-10-08 14:40:20 +08:00
flusheDData
a3637cf2b6 Update es.rs (#13104)
New terms added
2025-10-07 23:31:08 +08:00
fufesou
48669cdb34 fix: alarm audit number, ipv6 prefix attempts (#13097)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-10-06 22:10:54 +08:00
Michael Bacarella
a953845ba7 feat: Add IPv6 prefix-based rate limiting on login failures (#13070)
Enhance security by implementing rate limiting on IPv6 prefixes (/64, /56, /48)
to prevent brute force attacks that exploit cheap IPv6 address generation.

* Add private get_ipv6_prefixes() to calculate network prefixes
* Implement private check_failure_ipv6_prefix() for prefix-specific limits
  on IPv6 addresses
* Refactor check_failure() and update_failure() to support both IPs and prefixes
* Add ExceedIPv6PrefixAttempts to AlarmAuditType enum

Signed-off-by: Michael Bacarella <m@bacarella.com>
2025-10-05 23:43:29 +08:00
summoner
8d71534839 Translation: Update hu.rs (#13089)
Translate new strings
Fix translation
2025-10-03 22:41:53 +08:00
loako
d110118961 fix: Update Swedish translations that were missing (#13081) 2025-10-02 20:33:20 +08:00
Ibnul Mutaki
fa1ed2bc0c fix: Update Indonesian translations for consistency and clarity (#13077) 2025-10-01 22:59:00 +08:00
ysr9029
3f28978dad fix: Correct Japanese translations and typos in lang file (#13029) 2025-09-30 17:42:49 +08:00
dependabot[bot]
02cd121465 Git submodule: Bump libs/hbb_common from 1df14d9 to 7ea8686 (#13062)
Bumps [libs/hbb_common](https://github.com/rustdesk/hbb_common) from `1df14d9` to `7ea8686`.
- [Release notes](https://github.com/rustdesk/hbb_common/releases)
- [Commits](1df14d90c9...7ea868612d)

---
updated-dependencies:
- dependency-name: libs/hbb_common
  dependency-version: 7ea868612dfee7954facb9a7857d65ef875076eb
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-29 13:37:54 +08:00
21pages
5481c300b2 more assign from cli and devices.py (#13050)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-09-27 16:55:08 +08:00
Berk Efe Keskin
7b75257a4a Fixed translation errors on README-TR.md (#12976) 2025-09-26 15:51:36 +08:00
Alt
c02e5cad73 refactor: update lang id.rs (#13026) 2025-09-25 23:30:51 +08:00
fufesou
dee03c0f9f fix: Center the main window on first run. (#13003)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-09-24 14:47:29 +08:00
21pages
d1159764f6 add ab.py and audits.py (#12989)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-09-23 17:13:13 +08:00
Nathan Saslavsky
eacb07988d Add Wayland multi-monitor screen capture functionality (#12900)
* Add Wayland multi-monitor screen capture functionality

* fix wayland capture issues by reverting to CapturerPtr, the problem was that calling Display::all in get_capturer_for_display was dropping the pipewire capturer and causing the video to freeze.

* If running as AppImage or flatpak, ignore the 'multiple' argument

* Comment out warning log with unclear purpose Comment out warning log with unclear purpose

---------

Co-authored-by: fufesou <13586388+fufesou@users.noreply.github.com>
2025-09-22 21:53:14 +08:00
21pages
a375766ac2 disable iconv on android (#13001)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-09-22 21:49:58 +08:00
21pages
9b9276e752 fix crash on android armv7 (#12997)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-09-22 17:02:53 +08:00
Jonathan Gilbert
753a2ab2b7 Fixed super call in onWindowResized in tabbar_widget.dart. (#12979) 2025-09-22 11:26:19 +08:00
rustdesk
0cef5f79ee remove can't save option 2025-09-20 14:03:48 +08:00
fufesou
b11a8dfe54 fix: build (#12968)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-09-19 17:20:53 +08:00
Jonathan Gilbert
2d1c94f1ef Fix window positioning on Windows when the taskbar is on the top or left (#12933)
* Added win32_desktop.cpp/.h defining a method Win32Desktop::GetWorkArea.
Added code to wWinMain in main.cpp to position the window relative to the work area, which may not be at (0, 0) depending on the user's configuration.

* Corrected the constraint on the size value calculated by main.cpp.

* Fixed references to min to use std::min.

* Reworked GetWorkArea in win32_desktop.cpp to treat the supplied origin and size as containing an existing window rectangle, and to find the monitor that contains or is closest to that window.
Added function FitToWorkArea to win32_desktop.cpp/.h.
Updated main.cpp to use Win32Desktop::FitToWorkArea instead of explicitly constraining the size.
2025-09-19 16:11:26 +08:00
luzpaz
e14e850e10 fix: typos in src/ and subdirectories (#11727)
Found via codespell
2025-09-17 13:37:44 +08:00
21pages
3176391693 fix websocket reconnect (#12903)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-09-15 14:31:57 +08:00
VenusGirl❤
5277300943 Update README-KR.md (#12899) 2025-09-12 15:59:39 +08:00
VenusGirl❤
878e1ff290 Update README-KR.md (#12874) 2025-09-10 12:44:21 +08:00
fufesou
8d453010a4 fix: port forward, invalid msg (#12881)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-09-09 21:20:58 +08:00
Daniel
e2f6030590 Create CODE_OF_CONDUCT-DE.md (#12414)
Create a German Version of the CoC
2025-09-09 14:27:34 +08:00
VenusGirl❤
bf3f8706f8 Add CODE_OF_CONDUCT-KR.md (#12330) 2025-09-08 17:35:45 +08:00
21pages
5c9b4abab2 default shared password (#12868)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-09-07 16:47:35 +08:00
Kleofass
9fb4862a45 Update lv.rs (#12863) 2025-09-07 16:07:38 +08:00
Alex Rijckaert
65df6897a6 Update nl.rs (#12815) 2025-09-07 16:07:21 +08:00
XLion
529810f2f4 Update tw.rs (#12814) 2025-09-07 16:07:10 +08:00
fufesou
df0ff4f134 feat: cursor, linux, Xwayland (#12859)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-09-06 20:35:51 +08:00
fufesou
6c949a9602 feat: cursor, linux (#12822)
* feat: cursor, linux

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

* refact: cursor, text, white background

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2025-09-06 12:11:43 +08:00
Mahdi Rahimi
f933f46283 Updated Persian translations in fa.rs (#12802) 2025-09-06 12:09:58 +08:00
21pages
4080907d2b android mediacodec encode align 64 (#12852)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-09-06 12:09:21 +08:00
Mr-Update
ed5cd21cb6 Update de.rs (#12783) 2025-09-05 16:49:54 +08:00
solokot
aa8278e1d5 Update ru.rs (#12778) 2025-09-05 16:49:39 +08:00
fufesou
0f526fce6c refact: http, rust side, log errror (#12820)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-09-04 15:04:53 +08:00
IwantHappiness
15d471e520 Remove needless macros format! (#11456) 2025-09-03 22:17:11 +08:00
Mahdi Rahimi
c47e94813d Update Arabic translation in ar.rs (#12773) 2025-09-02 23:00:46 +08:00
rustdesk
c979cbcac7 disable-discovery-pane 2025-09-01 17:07:29 +08:00
21pages
6b2a1dfd84 update vcpkg, aom, vpx (#12795)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-09-01 15:35:27 +08:00
fufesou
7948d3144a fix: cursor, macos, text (#12794)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-09-01 15:34:48 +08:00
fufesou
d499098c4f Fix/cursor macos multi displays (#12791)
* fix: cursor, whiteboard, pos

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

* fix: whiteboard, macos, multi displays

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2025-09-01 13:02:06 +08:00
21pages
42be442385 fix ci (#12789)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-09-01 12:50:38 +08:00
fufesou
e2ec6a5be8 feat: whiteboard, macos (#12780)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-08-30 22:16:35 +08:00
bovirus
438cef8cf9 Italian language update (#12762) 2025-08-30 12:08:56 +08:00
Lynilia
7bacf7cdc9 Update fr.rs (#12758) 2025-08-30 12:08:44 +08:00
VenusGirl❤
c5e76972aa Update ko.rs (#12757)
Update Korean
2025-08-29 17:10:04 +08:00
fufesou
7ca8e0d437 refact: show my cursor (#12765)
1. Show not supported on Win7.
2. Enabling "Show my cursor" automatically enables "View mode".

Signed-off-by: fufesou <linlong1266@gmail.com>
2025-08-29 01:06:37 +08:00
fufesou
a98852e279 fix: mouse event, is in current window (#12760)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-08-29 01:06:05 +08:00
fufesou
d0e9c6dc57 feat: show my cursor (#12745)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-08-28 15:20:01 +08:00
fufesou
ac70f380a6 fix: file transfer, resume, path and finished size (#12739)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-08-26 17:59:39 +08:00
Dmitry Beskov
34cf9d6181 Enhance .desktop File with New Keywords for Improved App Discoverability (#12599)
* linux keywords in a desktop entry

* Update rustdesk.desktop

* Update rustdesk.desktop
2025-08-26 15:31:31 +08:00
fufesou
db4296533a feat: advanced option, main window, always on top (#12731)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-08-26 00:15:55 +08:00
fufesou
6381f43f01 feat: clipboard files, audit (#12730)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-08-25 22:29:53 +08:00
fufesou
f4fb31d7a1 feat: file transfer, resume (#12626)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-08-25 14:34:03 +08:00
Luke Bermingham
9e22f9639a Fix audio delay: added pulse audio and pipewire configuration for RustDesk service in Linux (#12724) 2025-08-25 14:33:37 +08:00
Mahdi Rahimi
9b854d3034 Update Arabic translation in ar.rs (#12714) 2025-08-24 14:16:10 +08:00
Re*Index. (ot_inc)
2c88a44a53 Update & Fix Japanese translate. (#12702) 2025-08-23 22:47:02 +08:00
RustDesk
0c2b86c8e7 Revert "Create Hi.rs (#12482)" (#12700)
This reverts commit 74752bbd2f.
2025-08-21 12:31:11 +08:00
Leo Louis
74752bbd2f Create Hi.rs (#12482)
* Create Hi.rs

Added hindi translation file

* Create Gu.rs

Added Gujarati translation file

* Create Ml.rs

Added Malayalam translation file

* Update lang.rs

* Rename Gu.rs to gu.rs

* Rename Ml.rs to ml.rs

changed name to correct format

* Rename Hi.rs to hi.rs

changed name to correct format
2025-08-21 12:20:48 +08:00
Mahdi Rahimi
ad396b4155 Updated Persian translations in fa.rs (#12697) 2025-08-21 12:20:05 +08:00
21pages
5ff1740b5b set allowMalformed to true when decode utf8 (#12693)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-08-20 14:55:52 +08:00
bovirus
e0ab3f0c92 Italian language update (#12679) 2025-08-20 14:17:02 +08:00
BigRetroMike
9b77e91d79 Update pl.rs (#12618)
Added missing translation and small correction
2025-08-19 12:14:19 +08:00
rustdesk
d187121645 simply remove it in case password log 2025-08-19 00:23:17 +08:00
fufesou
a22f2108c6 refact: suppress warns on macos (#12449)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-08-18 15:09:11 +08:00
rustdesk
bf24869c6a fix bundle id 2025-08-17 15:37:12 +08:00
Alex Rijckaert
4e9a370ff6 Update nl.rs (#12617)
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2025-08-17 15:29:17 +08:00
rustdesk
1aed6f3c2e compile warn 2025-08-17 10:08:12 +08:00
rustdesk
6367d50d76 fix myself 2025-08-17 10:04:40 +08:00
John Fowler
f33ed27419 Update hu.rs (#12610)
Add and translate a new string.
2025-08-16 12:09:15 +08:00
DeDuplicate
870c8cb158 Update he.rs (#12601) 2025-08-15 15:00:30 +08:00
fufesou
0b9d7925b5 fix: ios, file transfer, home dir (#12657)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-08-15 00:00:05 +08:00
rustdesk
16b625f8b4 fix ci 2025-08-14 18:58:26 +08:00
rustdesk
16d301a783 try AssociatedBundleIdentifiers per https://developer.apple.com/documentation/servicemanagement/updating-helper-executables-from-earlier-versions-of-macos#Respond-to-changes-in-System-Settings 2025-08-14 18:47:52 +08:00
Mr-Update
212bbaf44c Update de.rs (#12600) 2025-08-14 18:08:39 +08:00
rustdesk
1d6037003a new badge 2025-08-13 19:24:00 +08:00
Mahdi Rahimi
6f4b23b40b Updated Persian translations in fa.rs (#12589) 2025-08-13 12:26:27 +08:00
Mahdi Rahimi
4e82766ba4 Update Arabic translation in ar.rs (#12588) 2025-08-13 12:26:17 +08:00
Lynilia
dc86db5206 Update fr.rs (#12582) 2025-08-13 12:25:52 +08:00
solokot
5a75ea723b Update ru.rs (#12594) 2025-08-13 12:25:30 +08:00
Alex Rijckaert
d59f216c26 Update nl.rs (#12592) 2025-08-13 12:25:19 +08:00
VenusGirl❤
160edcc1cd Update ko.rs (#12590)
* Update ko.rs

* Update ko.rs

Update Korean
2025-08-13 12:25:09 +08:00
21pages
59d597de8a show direct connection for IPv6 via RelayResponse (#12634)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-08-13 10:08:23 +08:00
21pages
806351b6c1 fix remote tab tooltip (#12632)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-08-12 20:29:48 +08:00
21pages
e7909a0dbd opt update of direct/direct_failures (#12627)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-08-12 17:48:20 +08:00
rustdesk
d6d44be1b7 temporrarily revert file transfer resume 2025-08-11 23:28:19 +08:00
RustDesk
53efaf125c Revert "Feat: file transfer, resume (#12557)" (#12620)
This reverts commit 43ec57c769.
2025-08-11 23:25:41 +08:00
21pages
1fb0123ed7 remove skip udp punch if udp nat port is 0 (#12615)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-08-11 20:41:46 +08:00
21pages
a0659a277a show TCP/UDP/IPv6 in tooltip (#12613)
* add punch type log

Signed-off-by: 21pages <sunboeasy@gmail.com>

* show TCP/UDP/IPv6 in tooltip

Signed-off-by: 21pages <sunboeasy@gmail.com>

* Skip udp punch if udp nat port is 0

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-08-11 16:13:31 +08:00
rustdesk
77064cc2f8 fix ci 2025-08-10 17:50:25 +08:00
RustDesk
1954790808 try tcp and udp both 2025-08-10 17:44:36 +08:00
rustdesk
4263643200 macos-14 for arm 2025-08-10 00:04:00 +08:00
fufesou
43ec57c769 Feat: file transfer, resume (#12557)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-08-09 23:47:19 +08:00
rustdesk
302dad2016 update hbb_common 2025-08-09 23:46:51 +08:00
rustdesk
fdb8b498cb all use macos-13 2025-08-09 23:27:56 +08:00
rustdesk
f6af59b044 remove useless selfhost job 2025-08-09 23:26:33 +08:00
fufesou
ad1ed132d1 fix: file transfer, web (#12565)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-08-09 15:54:00 +08:00
rustdesk
466d456760 fix https://github.com/rustdesk/rustdesk/issues/12587 2025-08-09 10:25:21 +08:00
fufesou
6bc3b38b56 refact: macos, update, preparing for installation (#12581)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-08-08 14:25:22 +08:00
fufesou
39b91911cb fix: update macos (#12578)
* fix: update macos

1. Use `ditto` instead of `cp -r`.
2. Add prompt for extracting dmg.

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

* fix: error to err

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

* Refact: Remove "Extracting"

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2025-08-07 23:31:31 +08:00
SALİH ÖZKARA
e85989e9d9 Fix Turkish localization (#12555) 2025-08-07 20:16:14 +08:00
Alex Rijckaert
e7f672899b Update nl.rs (#12525) 2025-08-07 20:15:59 +08:00
VenusGirl❤
9538eba64e Update ko.rs (#12523)
Because it is button-shaped, even a short phrase such as “upgrade” can convey meaning in Korean.
2025-08-07 20:15:47 +08:00
rustdesk
b37b271fce add team to osx 2025-08-07 18:09:09 +08:00
21pages
77be752ff1 sciter hide cm (#12570)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-08-07 13:29:21 +08:00
Andrzej Rudnik
725a47268e Updated Polish translation (#12521)
* Update pl.rs

* Update pl.rs
2025-08-06 23:16:35 +08:00
asereze
2ba215a6d7 Update sc.rs (#12517) 2025-08-06 01:45:24 +08:00
H3XÐΛΞMѲИ
6533a1b98d i18n(tw): Fix translations and address inconsistencies (#12490) 2025-08-04 17:48:17 +08:00
tschettervictor
1f2f5a41d4 typo: openbad > openbsd (#12484) 2025-08-03 16:00:52 +08:00
VenusGirl❤
4e7680e322 Update ko.rs (#12480)
* Update ko.rs

* Update ko.rs

---------

Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2025-08-02 12:05:19 +08:00
Mahdi Rahimi
f32591c3d1 Update Arabic translation in ar.rs (#12451) 2025-08-01 17:18:49 +08:00
fufesou
6ec217263d fix: nokhwa, win, infinite loop (#12489)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-31 16:58:00 +08:00
fufesou
8899b90725 fix: build (#12483)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-31 00:27:55 +08:00
rustdesk
7ece7e730a fix https://github.com/rustdesk/rustdesk/issues/12481 2025-07-30 21:06:09 +08:00
Mahdi Rahimi
d55b98b187 Updated Persian translations in fa.rs (#12450) 2025-07-30 13:13:28 +08:00
dependabot[bot]
d9674a2d77 Git submodule: Bump libs/hbb_common from f91459c to 57c8a23 (#12459)
Bumps [libs/hbb_common](https://github.com/rustdesk/hbb_common) from `f91459c` to `57c8a23`.
- [Release notes](https://github.com/rustdesk/hbb_common/releases)
- [Commits](f91459c4ab...57c8a23ab9)

---
updated-dependencies:
- dependency-name: libs/hbb_common
  dependency-version: 57c8a23ab970587ea6380943b04dc354020bbe7c
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-29 16:03:07 +08:00
rustdesk
26e5f7bbeb show websocket option on desktop 2025-07-29 11:53:45 +08:00
21pages
7a3e67e1d3 fix connect timeout of udp_nat_connect and udp_nat_listen (#12447)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-07-28 20:06:30 +08:00
fufesou
af53b1e8c9 fix: rendezvous server timeout (#12443)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-28 12:14:07 +08:00
Lynilia
9db7217cab Update fr.rs (#12438) 2025-07-28 12:12:44 +08:00
fufesou
d0651e32c5 fix: printer, printable area (#12442)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-28 11:42:30 +08:00
rustdesk
0646a5b313 try to fix reboot not working because retry too slow 2025-07-28 11:16:04 +08:00
RustDesk
e9692b94ca Revert "Fix/printer printable area (#12433)" (#12441)
This reverts commit 6e62c10fa0.
2025-07-28 10:38:19 +08:00
fufesou
6e62c10fa0 Fix/printer printable area (#12433)
* fix: printer, printable area

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

* refact: windows, sc config RustDesk --start= delayed-auto

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-27 19:47:23 +08:00
Mr-Update
52bfc02eea Update de.rs (#12424) 2025-07-26 18:42:19 +08:00
21pages
2282c8e308 opt assert for debug (#12420)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-07-26 18:41:57 +08:00
21pages
9409912344 update kcp-sys (#12419)
1. Update kcp-sys to send KCP in frames to avoid potential crashes.
2. Fix the issue when the controling side is closed, the kcp connection close is not immediately recognized by the controlled end.
  * Unless the controling side receives the close reason, force the sending of the close reason to the controlled end when using KCP, and delay for 30ms to ensure the message is sent successfully.
  * Move the CloseReason receiving forward, as this message needs to be received when unauthorized, especially for kcp.

Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-07-25 13:22:52 +08:00
XLion
2afd538cf1 Update tw.rs (#12412) 2025-07-25 13:13:31 +08:00
John Fowler
ab48f10f25 Update hu.rs (#12403)
Translate new string(s).
2025-07-24 17:43:06 +08:00
TheBitBrine
1b40d146ee Fix retry button blocked by overly broad "exist" filter (#12397)
The retry logic was blocking retry buttons for errors containing "exist", 
which incorrectly filtered out "An existing connection was forcibly closed" 
network errors. Changed to "not exist" to only block "ID does not exist" 
type errors while allowing legitimate network disconnection errors to show 
retry buttons.

Fixes issue where users couldn't retry after network disconnections.
2025-07-24 08:51:25 +08:00
fufesou
b4e13706bd refact: active terminal on conn the same remote (#12392)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-23 22:44:05 +08:00
21pages
f2473974b8 fix ci (#12387)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-07-23 17:10:26 +08:00
rustdesk
50fc6d691f 1.4.1 2025-07-23 15:51:44 +08:00
fufesou
247f0b7eb1 fix: terminal, check service_id (#12384)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-23 15:43:55 +08:00
fufesou
80c4a83a39 fix: build (#12385)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-23 13:53:04 +08:00
solokot
3fb3d51567 Update ru.rs (#12374) 2025-07-23 11:13:36 +08:00
VenusGirl❤
596e7b33db Update ko.rs (#12348) 2025-07-23 11:13:20 +08:00
bovirus
c01bbeea78 Italian language update (#12347) 2025-07-23 11:12:56 +08:00
flusheDData
47886c4068 Update es.rs (#12339)
New terms added
2025-07-23 11:12:16 +08:00
fufesou
348c477f75 fix: terminal, web, fonts (#12376)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-22 23:42:05 +08:00
fufesou
61194182eb fix: debug, terminal web (#12375)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-22 19:26:50 +08:00
fufesou
9bca5ac000 refact: terminal, save window pos on close (#12370)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-22 15:16:13 +08:00
fufesou
b65ef36049 fix: terminal, restore, multi-sessions, msgs (#12364)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-22 09:59:20 +08:00
fufesou
391ef70007 fix: terminal, persistent (#12357)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-21 17:15:02 +08:00
VenusGirl❤
9bcfe9d148 Update README-KR.md (#12329)
Update
2025-07-20 21:59:26 +08:00
rustdesk
94e23a6cd0 remove devcontainer.md 2025-07-19 14:26:11 +08:00
VenusGirl❤
55ddb9751a Create DEVCONTAINER-KR.md (#12331) 2025-07-19 14:25:47 +08:00
rustdesk
9d82ef1a22 remove terminal.md 2025-07-19 14:23:22 +08:00
fufesou
555bb66668 fix: terminal, handle newline (#12342)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-19 11:14:14 +08:00
21pages
1581272104 opt hint of elevation username (#12338)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-07-18 18:40:43 +08:00
bovirus
a37f4d79db Italian language update (#12321) 2025-07-18 18:16:59 +08:00
XLion
4723d07215 Update tw.rs (#12327)
* Update tw.rs

* Update tw.rs
2025-07-18 18:16:28 +08:00
Mr-Update
3177786219 Update de.rs (#12324) 2025-07-18 18:16:00 +08:00
solokot
061dc9962d Update ru.rs (#12332) 2025-07-18 18:15:56 +08:00
VenusGirl❤
0a62103ccd Update ko.rs (#12316) 2025-07-18 18:15:01 +08:00
John Fowler
2e2b4ac2fe Update hu.rs (#12323)
Translate new strings.
2025-07-18 18:14:47 +08:00
fufesou
e91f4fc104 fix: terminal, restore, cross users (#12335)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-18 16:25:53 +08:00
fufesou
bdd3bb946e refact: restore terminals (#12334)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-18 11:51:53 +08:00
VenusGirl❤
398b0d8d8b Update SECURITY-KR.md (#12308) 2025-07-17 21:11:58 +08:00
VenusGirl❤
dc41495566 Update CONTRIBUTING-KR.md (#12302) 2025-07-17 20:58:21 +08:00
VenusGirl❤
effbb45eb7 Update README-KR.md (#12301)
Translation Update
2025-07-17 20:53:15 +08:00
WC3D
4d960c3c8c Potential fix for code scanning alert no. 29: Workflow does not contain permissions (#12326)
If a GitHub Actions job or workflow has no explicit permissions set, then the repository permissions are used. Repositories created under an organization inherit the organization's permissions. Organizations or repositories created before February 2023 have default permissions set to read-write. Often, these permissions do not adhere to the principle of least privilege and can be reduced to read-only, leaving write permission only for specific types, such as issues (write) or pull requests (write).

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2025-07-17 08:54:53 +08:00
fufesou
475bef63d7 fix: linux, env TERM (#12325)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-17 08:46:32 +08:00
fufesou
e711f73451 fix: macos, defunct process (#12315)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-16 14:17:16 +08:00
fufesou
661be6ae36 fix: build (#12313)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-16 09:28:24 +08:00
fufesou
e31b04b6a7 fix: new translation message (#12312)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-16 09:25:47 +08:00
fufesou
d5eb87ee8b fix: try to fix stuck on read (#12310)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-15 23:36:16 +08:00
fufesou
65c721e088 fix: terminal connection on Linux and MacOS (#12307)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-15 23:09:04 +08:00
21pages
69af5f2fa6 update hwcodec (#12303)
* Test necessary codecs in single thread
* Terminate test process with parent process

Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-07-15 18:49:45 +08:00
fufesou
abb7748ee9 refact: terminal, win, run as admin (#12300)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-15 16:32:14 +08:00
VenusGirl❤
8d559725d5 Update ko.rs (#12298)
* Update ko.rs

* Update ko.rs

* Update ko.rs
2025-07-15 15:42:19 +08:00
Mahdi Rahimi
8c68b83265 Update Arabic translation in ar.rs (#12284) 2025-07-15 15:42:07 +08:00
Mahdi Rahimi
ae255c83ee Updated Persian translations in fa.rs (#12283) 2025-07-14 15:28:01 +08:00
LittleFishYu2008
856362006a Update cn.rs (#12281)
* Update cn.rs

* Update cn.rs

* Update cn.rs

* Update cn.rs
2025-07-13 16:08:41 +08:00
Kleofass
331b624cd6 Update lv.rs (#12270) 2025-07-12 13:40:45 +08:00
rustdesk
0117e94e6f format 2025-07-11 22:33:35 +08:00
John Fowler
aa680533ae Update hu.rs (#12267)
Translate new strings.
2025-07-11 22:32:14 +08:00
dependabot[bot]
94e76c3b6f Git submodule: Bump libs/hbb_common from f850a16 to 25e761f (#12264)
Bumps [libs/hbb_common](https://github.com/rustdesk/hbb_common) from `f850a16` to `25e761f`.
- [Release notes](https://github.com/rustdesk/hbb_common/releases)
- [Commits](f850a167ac...25e761f467)

---
updated-dependencies:
- dependency-name: libs/hbb_common
  dependency-version: 25e761f46778b567061770bc64d66332a4503332
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-10 16:21:19 +08:00
Alex Rijckaert
0258b9adca Update nl.rs (#12216) 2025-07-08 16:19:49 +08:00
Mr-Update
f15b9f05fb Update de.rs (#12215) 2025-07-07 16:57:04 +08:00
solokot
dd7a124334 Update ru.rs (#12227) 2025-07-06 18:03:45 +08:00
bovirus
7447a36782 Italian language update (#12210) 2025-07-06 18:00:05 +08:00
Lynilia
e2830347e6 Update fr.rs (#12203) 2025-07-06 17:59:51 +08:00
rustdesk
9389f3306d fix https://github.com/rustdesk/rustdesk/issues/12233 2025-07-05 09:24:18 +08:00
RustDesk
f3819e19d4 improve sas (#12226)
* improve sas

* Update windows.rs
2025-07-04 16:47:08 +08:00
Alex Rijckaert
9caf0dddc3 Update nl.rs (#12202) 2025-07-04 16:21:32 +08:00
fufesou
f766d28c36 Fix/linux keep terminal sessions (#12222)
* fix: linux, keep terminal sessions

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

* fix: terminal service stucked at reader join

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-03 17:27:50 +08:00
COYG⚡️
7ad3023285 docs: Render correct "CAUTION" (#12204) 2025-07-02 18:59:59 +08:00
COYG⚡️
86e79b0162 docs: correct jump to other language markdown files (#12205) 2025-07-02 18:59:34 +08:00
COYG⚡️
09098e86ca docs: Correct the path to CONTRIBUTING.md links in the README files for each language to ensure that you point to the correct file location. (#12207) 2025-07-02 18:59:18 +08:00
rustdesk
7ce13a21f8 reorder lang/template.rs 2025-07-01 13:23:59 +08:00
Naveenkumar
cf0d090c08 Update ta.rs (#12200)
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2025-07-01 13:18:23 +08:00
fufesou
f26d2a7b84 feat: stylus support (#12196)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-07-01 13:13:41 +08:00
RustDesk
5faf0ad3cf terminal works basically. (#12189)
* terminal works basically.
todo:
- persistent
- sessions restore
- web
- mobile

* missed terminal persistent option change

* android sdk 34 -> 35

* +#![cfg_attr(lt_1_77, feature(c_str_literals))]

* fixing ci

* fix ci

* fix ci for android

* try "Fix Android SDK Platform 35"

* fix android 34

* revert flutter_plugin_android_lifecycle to 2.0.17 which used in rustdesk 1.4.0

* refactor, but break something of desktop terminal (new tab showing loading)

* fix connecting...
2025-07-01 13:12:55 +08:00
Alex Rijckaert
ee5cdc3155 Update nl.rs (#12194) 2025-06-30 14:59:21 +08:00
rustdesk
e0f5fa39f3 terminal of hbb common 2025-06-29 14:09:59 +08:00
Melroy dsilva
d21a1023d2 docs: improve grammar and clarity in READM (#12155) 2025-06-28 15:26:00 +08:00
Andrzej Rudnik
884373794a Update pl.rs (#12162) 2025-06-27 18:49:25 +08:00
fufesou
9060f9ec8a fix: linux tray, defunct process (#12177)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-06-26 18:27:22 +08:00
fufesou
fd4e0146e1 fix: replace sh with CMD_SH (#12173)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-06-26 15:54:16 +08:00
fufesou
58fd2d3ccd fix: linux, get_env, break loop (#12174)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-06-26 15:47:01 +08:00
fufesou
bb6e080c1c fix: linux workaround cmd path (#12172)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-06-26 09:49:22 +08:00
21pages
7b7c93b78d fix record directory of custom client (#12171)
* For custom client, the incoming record directory of installing Windows app and the Android record directory still use RustDesk,  it works, but replace 'RustDesk' with the custom client's name.

Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-06-26 09:29:41 +08:00
Mahdi Rahimi
94ae3886c5 Update Arabic translation in ar.rs (#12134) 2025-06-25 12:43:35 +08:00
RustDesk
79c6da98d2 Update common.rs (#12159) 2025-06-24 21:38:59 +08:00
RustDesk
18ea3a4b59 Update common.rs 2025-06-24 21:38:36 +08:00
Mahdi Rahimi
2ae7f00ceb Updated Persian translations in fa.rs (#12133) 2025-06-24 13:23:35 +08:00
fufesou
4d8bfab86e fix: sequentially post conn audit (#12152)
* fix: sequentially post conn audit

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

* Update connection.rs

* refact: simplify loop

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

* Update connection.rs

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2025-06-23 23:55:07 +08:00
rustdesk
50b1c02243 fix dup msg for relay request 2025-06-23 20:29:24 +08:00
Adam Lewicki
fa61693ccd Update pl.rs (#12118) 2025-06-22 13:48:31 +08:00
bovirus
7822d3d923 Italian language update (#12095) 2025-06-21 16:29:23 +08:00
solokot
98d99fae64 Update ru.rs (#12096) 2025-06-21 16:29:11 +08:00
fufesou
7330dc70f3 fix: android 7.1, input, crash (#12129)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-06-20 17:50:28 +08:00
fufesou
46cd090f98 Revert "try fix firefox v2 paste problem" (#12126)
This reverts commit 590ecc43ff.
2025-06-19 22:31:40 +08:00
fufesou
d6ba063655 fix: win, privacy mode 2 (#12123)
* fix: win, privacy mode 2

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

* Update src/privacy_mode/win_virtual_display.rs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-19 18:39:15 +08:00
rustdesk
590ecc43ff try fix firefox v2 paste problem 2025-06-19 13:21:47 +09:00
rustdesk
1eee03818d fix https://github.com/rustdesk/rustdesk/discussions/11838 2025-06-19 12:28:38 +09:00
fufesou
5dd15d1282 fix: privacy mode, msgbox sometimes does not show (#12117)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-06-18 16:25:15 +08:00
largemouth
8754579181 chore: fix some typos in comment (#12102)
Signed-off-by: largemouth <largemouth@aliyun.com>
2025-06-17 21:02:35 +08:00
rustdesk
57b826c56b try removing bom 2025-06-16 23:14:49 +09:00
rustdesk
bfd6ca79f8 debugg invalid id issue https://discord.com/channels/804630702657110016/804630702657110018/1384157888603357337 2025-06-16 22:44:22 +09:00
rustdesk
d84b26a9cd try to fix 1.3.8 not work on win7 sp1, https://github.com/rustdesk/rustdesk/discussions/12097 2025-06-16 18:36:15 +09:00
Mr-Update
181b3afc2d Update de.rs (#12092) 2025-06-16 13:30:14 +08:00
XLion
31934e9bd8 Update tw.rs (#12091) 2025-06-16 13:29:59 +08:00
rustdesk
14a8f00e5b fix punch option for non-public 2025-06-15 14:58:12 +08:00
rustdesk
44e00f8ec2 remove xpsprint.dll hard dep, https://github.com/rustdesk/rustdesk/discussions/12042#discussioncomment-13464313 2025-06-14 21:58:51 +08:00
rustdesk
645a76d43f udp / ipv6 punch option 2025-06-14 21:42:18 +08:00
Ibnul Mutaki
bf77f582d0 trans(ID): fix some phrase and add more translation (#12050)
* trans: fix some phrase and add more translation

* trans: change : upgrade tip

* fixing typo Downliad -> Download
2025-06-14 21:17:45 +08:00
rustdesk
c58fd145f2 CLAUDE.md 2025-06-14 18:04:12 +08:00
fufesou
a5a3352655 fix: linux, nokhwa, camera index (#12045)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-06-14 13:19:59 +08:00
21pages
2533493c66 Remove non-existent tags when importing ab peers from another ab (#12062)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-06-13 14:34:27 +08:00
rustdesk
832458c59e 1024 -> 1500 2025-06-13 00:42:52 +08:00
rustdesk
5beebf967d fix kcp_stream 2025-06-13 00:30:21 +08:00
rustdesk
4e9bdcbc1f fix ci 2025-06-13 00:12:07 +08:00
rustdesk
070b0354fd bring back allow-https-21114 https://github.com/rustdesk/rustdesk-server-pro/discussions/570#discussioncomment-13449526 2025-06-12 23:11:07 +08:00
rustdesk
f9405711c6 fix ci 2025-06-12 21:35:32 +08:00
rustdesk
7792ac1481 udp punch and ipv6 punch 2025-06-12 21:32:28 +08:00
lichon
05a812247a fix: use default camera, first element in query result might not be a camera (#12010) 2025-06-12 13:35:42 +08:00
WC3D
645cfd3b3d Bump ring from 0.17.8 to 0.17.13 in the cargo group across 1 directory (#12028)
Bumps the cargo group with 1 update in the / directory: [ring](https://github.com/briansmith/ring).


Updates `ring` from 0.17.8 to 0.17.13
- [Changelog](https://github.com/briansmith/ring/blob/main/RELEASES.md)
- [Commits](https://github.com/briansmith/ring/commits)

---
updated-dependencies:
- dependency-name: ring
  dependency-type: indirect
  dependency-group: cargo
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-11 13:28:51 +08:00
rustdesk
294ffcd9d3 hide-powered-by-me 2025-06-10 22:01:30 +08:00
Syed Ghufran Hassan
738afb54d7 Update main.rs (#12027)
common::global_init() might fail silently. Since return is used without any error logging, the user won’t know why the application didn't start so that is why added error print statement in case if it fails
2025-06-10 10:56:10 +08:00
mehdi-song
83f45b2212 Update fa.rs (#11971)
;-)
2025-06-07 19:21:42 +08:00
fufesou
8b2643e060 refact: remove unnecessary printing (#12000)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-06-06 14:52:01 +08:00
Kleofass
e79724644d Update lv.rs (#11966) 2025-06-05 13:06:21 +08:00
Lynilia
861fc91578 Update fr.rs (#11940) 2025-06-04 13:11:14 +08:00
Mahdi Rahimi
fa7770d901 Update Arabic translation in ar.rs (#11934) 2025-06-03 13:31:18 +08:00
21pages
e0f35b9046 test nat type for outgoing-only client (#11962)
* test nat type for outgoing-only client

Signed-off-by: 21pages <sunboeasy@gmail.com>

* test nat type for ios

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-06-03 09:27:02 +08:00
XLion
32e96e3705 Update tw.rs (#11931) 2025-06-02 22:16:24 +08:00
rustdesk
d52d9da043 upgrade android plugin to 7.3.1 2025-06-01 20:16:42 +08:00
rustdesk
68eaedfddc enable force-always-relay option for address book and accessible devices 2025-06-01 19:27:00 +08:00
rustdesk
e08cf3c0eb update kotlin 2025-06-01 17:58:03 +08:00
rustdesk
f919f297ac fix https://github.com/rustdesk/rustdesk/issues/11943 2025-06-01 16:44:55 +08:00
Mahdi Rahimi
c39c49fd17 Updated Persian translations in fa.rs (#11933) 2025-05-31 13:08:30 +08:00
rustdesk
90cb0ee56d fix https://github.com/rustdesk/rustdesk/issues/11927 2025-05-30 23:32:17 +08:00
Robert Galoyan
edab44afdf Update Russian docs to keep them in par with the original readme (#11901)
* Keep `README-RU` up to date with original readme

* Update `CONTRIBUTING-RU.md`

Minor reformat and grammar/orphography fixes
2025-05-30 13:39:38 +08:00
21pages
ec0456e606 clear the accessible devices tab when retrieving accessible devices disabled (#11913)
* clear the accessible devices tab when retrieving accessible devices is disabled

Signed-off-by: 21pages <sunboeasy@gmail.com>

* Update group_model.dart

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2025-05-29 17:07:32 +08:00
Jun, Koo
4e1a814aeb Update: Korean translation for various strings (#11892)
Updates the Korean translation file (`ko.rs`) to include new and corrected translations for various UI elements and messages. This improves the accuracy and completeness of the Korean localization.
2025-05-29 14:44:09 +08:00
rustdesk
4f8f34ec01 improve err 2025-05-28 23:27:12 +08:00
rustdesk
836950354b force secure tcp 2025-05-28 23:02:46 +08:00
Jun, Koo
527be17eaf Docs: Improve Korean translation for clarity and consistency (#11889)
* Docs: Improve Korean translation for clarity and consistency

Corrected minor grammatical errors and improved phrasing in `CONTRIBUTING-KR.md` and `README-KR.md` for better readability and consistency.

* Docs(KR): Update Korean README/CONTRIBUTING to align with latest English versions and refine translations
2025-05-28 21:42:14 +08:00
rustdesk
a0f4984ba5 update reqwest 2025-05-27 22:37:12 +08:00
Alex Rijckaert
4121e3fd14 Update nl.rs (#11873) 2025-05-27 13:08:03 +08:00
bovirus
a7a2f77ea3 Italian language update (#11862) 2025-05-26 21:05:13 +08:00
Mr-Update
46622f7576 Update de.rs (#11856) 2025-05-25 15:03:53 +08:00
solokot
45c9c505db Update ru.rs (#11855) 2025-05-24 14:27:22 +08:00
rustdesk
777c25bba2 no api for unregistered device 2025-05-24 09:21:06 +08:00
rustdesk
01146574f2 prepare no-register-device 2025-05-23 22:15:31 +08:00
rustdesk
39151531d7 fix ci 2025-05-23 17:22:13 +08:00
flusheDData
a5fefaddf5 New terms added (#11823)
* Update es.rs

* Update es.rs

* Update es.rs

New terms added

---------

Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2025-05-23 17:13:15 +08:00
Y-Ploni
f68d333bf1 Update he.rs (#11795)
* Update he.rs

* Update he.rs
2025-05-23 17:11:40 +08:00
fufesou
3c028fe5b5 feat: numeric one-time password (#11846)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-05-23 17:10:47 +08:00
fufesou
6ff679c6b4 fix: win, upload sysinfo (#11849)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-05-23 16:46:50 +08:00
rustdesk
48da2709d7 add youtube to readme 2025-05-23 11:14:35 +08:00
luzpaz
042d031a04 fix: source typo in src/clipboard.rs (#11726)
Found via codespell
2025-05-22 16:17:59 +08:00
VenusGirl❤
b2d5eb9714 Update SECURITY-KR.md (#11725) 2025-05-22 16:17:31 +08:00
fufesou
511a0b3693 refact: macos, comments, resolution list (#11830)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-05-21 18:23:14 +08:00
fufesou
06ab987e32 fix: macos, hidpi, resolutions (#11825)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-05-21 16:53:02 +08:00
rustdesk
b4a30cac73 Try to fix https://github.com/rustdesk/rustdesk/discussions/5602#discussioncomment-12482865 2025-05-21 15:00:12 +08:00
rustdesk
f801c251ed enable web socket for all except web 2025-05-20 20:49:21 +08:00
Lars
d3d7b09fe7 fix: mobile never connecting with password from url scheme (#11797) 2025-05-20 16:35:36 +08:00
fufesou
6144a1c97e fix: osx, reset modifiers' state after locking screen (#11806)
https://github.com/rustdesk/rustdesk/issues/11802

Signed-off-by: fufesou <linlong1266@gmail.com>
2025-05-19 21:02:07 +08:00
fufesou
118552ad0e refact: osx, handle key events, sleep (#11798)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-05-19 10:01:42 +08:00
rustdesk
9217205229 all key/mouse in QUEUE since --server has GUI too (--tray) 2025-05-17 14:40:44 +08:00
fufesou
4f6ae08110 fix: macos, key input lags, when service running (#11786)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-05-17 11:03:02 +08:00
solokot
90ad55d4aa Update ru.rs (#11769) 2025-05-16 15:27:40 +08:00
YGF
f1a4494e3c fix: parameter error (#11777) 2025-05-16 09:52:40 +08:00
fufesou
5fa17e440a fix: nokhwa, windows, x86 target runs on x64 (#11774)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-05-15 11:04:21 +08:00
fufesou
a73fa3cbf6 refact: oidc, launch url (#11772)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-05-15 09:06:37 +08:00
rustdesk
ae7faea6d5 --address_book_alias 2025-05-14 19:07:39 +08:00
fufesou
b525185d7f feat: web oidc (#11755)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-05-14 17:35:50 +08:00
Y-Ploni
dad841e493 Update he.rs (#11761) 2025-05-14 17:34:48 +08:00
21pages
550dd5ad72 update hbb_common, fix sync socks from advanced options to config file (#11757)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-05-14 15:32:04 +08:00
rustdesk
b4eeaee737 vn -> vi, fix https://github.com/rustdesk/rustdesk/issues/11756 2025-05-14 12:51:53 +08:00
RustDesk
cee69bb8b4 Update winget.yml 2025-05-14 01:33:08 +08:00
RustDesk
43501b663e Update winget.yml 2025-05-14 01:21:04 +08:00
RustDesk
9c0711e1db Update winget.yml 2025-05-14 01:18:54 +08:00
rustdesk
d00b8bb580 stupid me 2025-05-13 22:40:49 +08:00
rustdesk
c735fbd54c improve self-host server switch case https://github.com/rustdesk/rustdesk/issues/11749 2025-05-13 19:56:48 +08:00
fufesou
9d0d729522 Refact/update printer (#11748)
* refact: update printer

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

* fix: uninstall the printer for normal users

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2025-05-13 19:33:00 +08:00
fufesou
4c354ee1ae refact: install printer (#11745)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-05-13 14:14:54 +08:00
fufesou
f56c5c1bbb fix: win, prompt uac, update_install_option (#11741)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-05-13 10:20:57 +08:00
fufesou
a615b5e119 fix: nokhwa, dll search path (#11738)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-05-12 23:17:59 +08:00
Lynilia
12a9745b88 Update fr.rs (#11719) 2025-05-12 21:46:29 +08:00
John Fowler
b05a77ece2 Update hu.rs (#11718)
* Update hu.rs

Translation of the new character strings into Hungarian.

* Update hu.rs

Translation of the new character strings into Hungarian.
I replaced bad characters with good characters.
2025-05-12 21:46:18 +08:00
fufesou
ea106354af fix: win, only start tray if is installed exe (#11737)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-05-12 21:46:05 +08:00
XLion
e6aefcfa30 Update tw.rs (#11714) 2025-05-11 20:31:08 +08:00
Kleofass
4c5ec42100 Update lv.rs (#11712) 2025-05-11 20:30:59 +08:00
bovirus
f61728e24c Italian language update (#11709) 2025-05-11 20:30:47 +08:00
VenusGirl❤
2d7d1d0545 Create SECURITY-KR.md (#11704) 2025-05-11 20:30:35 +08:00
VenusGirl❤
968a9deee5 Update ko.rs (#11703)
* Update ko.rs

* Update ko.rs
2025-05-11 20:30:12 +08:00
Mr-Update
e79f254e50 Update de.rs (#11702) 2025-05-11 20:29:57 +08:00
Alex Rijckaert
8f712a51a3 Update nl.rs (#11701) 2025-05-11 20:29:33 +08:00
stanil77
7d20e0f26f Update bg.rs (#11700)
Updated translations, fixed some errors.
2025-05-11 20:29:21 +08:00
fufesou
c1b46b6b9d fix: login 2fa (#11715)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-05-11 20:27:41 +08:00
fufesou
dd0e6c31ba refact: mouse scroll, remote tabs (#11708)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-05-11 13:32:36 +08:00
rustdesk
54cf1c8225 dialog func 2025-05-11 11:47:35 +08:00
rustdesk
a73be6fc94 fix some build command 2025-05-11 01:15:29 +08:00
rustdesk
2c976eb1e2 prepare self-hosting web client 2025-05-10 21:49:23 +08:00
21pages
9dbb6217f7 fix pull ab twice in log (#11699)
The reason for calling `pullAb` twice is that when `pullAb` is called for the first time, `setCurrentName` is also called. In `setCurrentName`, if the current address book has not been initialized, it will also attempt to pull. Because `quiet` is false during the first call and `setCurrentName` is not `await` synchronously, the `abLoading` can prevent the two calls. However, `abLoading` depends on `quiet`, so we need to add a new variable `_abLoadingLock`.

Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-05-10 21:40:55 +08:00
Francisco Torres
1a8e3005cd docs: update spanish readme (#11696) 2025-05-10 12:12:41 +08:00
solokot
e9b4e4d170 Update ru.rs (#11683)
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2025-05-10 12:10:47 +08:00
mehdi-song
fb1661c897 Update fa.rs (#11684)
* Update fa.rs

* Update fa.rs
2025-05-09 16:34:36 +08:00
fufesou
ca7b4872d9 feat, trackpad speed (#11680)
* feat, trackpad speed

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

* comments

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

* Trackpad speed, user default value

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2025-05-09 15:36:45 +08:00
21pages
9475743b4e allow use websocket (#11677)
1. Enable the RustDesk client to use WebSocket for either controlling or being controlled.
2. Fix TCP sending `register_pk` frequently

Note:
1. Because hbb_common directly uses `use_ws` to read config directly, rustdesk also directly reads config

Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-05-09 12:18:49 +08:00
rustdesk
86bbdf7a5d refactor 2025-05-09 01:15:12 +08:00
rustdesk
4f6818477f less ipc 2025-05-09 00:49:18 +08:00
rustdesk
d46862e47d refactor test_nat 2025-05-09 00:07:06 +08:00
fufesou
61cdb60362 fix: rdp (#11670)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-05-07 21:24:14 +08:00
rustdesk
419bb3f0b0 fix ci 2025-05-07 16:43:27 +08:00
rustdesk
0869ceb5da hide-remote-printer-settings 2025-05-07 16:33:14 +08:00
Andrzej Rudnik
36e52e41ad Update pl.rs (#11663) 2025-05-07 10:45:54 +08:00
fufesou
bd85e9c322 fix: sciter, check, has_file_clipboard (#11666)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-05-07 10:07:24 +08:00
Alex Rijckaert
6ffbcd1375 Update nl.rs (#11658) 2025-05-06 17:07:30 +08:00
Alex Rijckaert
a7d0f3b149 Update nl.rs (#11654) 2025-05-05 22:27:06 +08:00
Mr-Update
5e60a47408 Update de.rs (#11650) 2025-05-05 22:26:51 +08:00
Arno
aa30f68c05 Update Korean translation (#11647)
Improved and completed the Korean translation in ko.rs.
Fixed missing and untranslated entries.
2025-05-05 22:24:53 +08:00
solokot
eee5b5f64c Update ru.rs (#11646) 2025-05-05 22:24:29 +08:00
bovirus
5298a5f83b Italian language update (#11641) 2025-05-05 22:24:10 +08:00
fufesou
d56df22838 fix: win, tray, detect cmdline (#11638)
target x86, run on x64

Signed-off-by: fufesou <linlong1266@gmail.com>
2025-05-05 08:51:25 +08:00
fufesou
ca00706a38 feat, update, win, macos (#11618)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-05-04 07:32:47 +08:00
Mr-Update
62276b4f4f Update de.rs (#11627) 2025-05-02 07:15:20 +08:00
rustdesk
e55722308e fix ci 2025-05-02 03:53:19 +08:00
rustdesk
7c8d2daaf6 update lock 2025-05-02 03:49:51 +08:00
rustdesk
04e2792f5f use tcp only for socks5 2025-05-02 03:41:55 +08:00
XLion
7196dbed6e Update tw.rs (#11615) 2025-05-02 02:55:50 +08:00
summoner001
ec1de6413a Update hu.rs (#11620)
* Update hu.rs

Translate strings and fixing

* Update hu.rs

fix sentence

* Update hu.rs

fix sentence
2025-05-02 02:55:36 +08:00
bovirus
d30ead1d96 Italian language update (#11619) 2025-05-02 02:55:26 +08:00
fufesou
20fcddffbd fix: build (#11611)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-04-30 23:49:18 +08:00
solokot
83aae23ba6 Update ru.rs (#11608) 2025-04-30 22:21:54 +08:00
Shahar Naveh
df847e9a60 Add some hebrew translation (#11490)
* Update he.rs

* Update he.rs

* Update he.rs

* Update he.rs

* Update he.rs

---------

Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2025-04-30 22:19:57 +08:00
fufesou
2ad1c907b8 feat: hostname as id (#11605)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-04-30 17:34:17 +08:00
fufesou
c626c2414d 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>
2025-04-30 17:23:35 +08:00
rustdesk
2864e1984a improve cap 2025-04-29 23:27:43 +08:00
rustdesk
f0c5580f57 cap display name 2025-04-29 23:05:25 +08:00
fufesou
abde556695 fix: lan discovery (#11592)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-04-28 21:48:14 +08:00
YinMo19
c9d5e15ac0 Using new Stream type adapted to the update of submodules (#11581)
* [fix bug] fix all err stream type.

* [update] update hbb_common.

* [bug fix] Stream in other platform.
2025-04-28 00:47:33 +08:00
fufesou
16e9e716b6 fix: check server running on Windows (#11578)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-04-27 12:04:05 +08:00
fufesou
f438bf582b fix: http proxy (#11570)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-04-26 13:04:41 +08:00
21pages
c0789a5fc0 Add custom client judgment for hide cm (#11563)
There is latency in the HTTP request; add a custom client check to avoid the PRO variable being unset during application startup

Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-04-25 17:13:19 +08:00
fufesou
198967ea35 fix: allow logon screen password, on lock screen (#11566)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-04-25 10:37:09 +08:00
fufesou
279fb72a4f fix: remote printer, update install option (#11461)
* fix: remote printer, update install option

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

* Add comments

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

* Add comments

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

* Win, run_cmds, remove extra whitespace and newline

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2025-04-24 18:24:22 +08:00
rustdesk
5c2538e7af https://github.com/rustdesk/rustdesk/discussions/9802 2025-04-23 22:24:43 +08:00
21pages
296aa7f8a0 fix build and update comment (#11542)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-04-22 23:18:36 +08:00
rustdesk
2cb096178a ifix PRO 2025-04-22 22:05:46 +08:00
RustDesk
57ee031827 Revert "Translations update from Toolate (#11510)" (#11535)
This reverts commit 86d9e62780.
2025-04-22 16:53:38 +08:00
Yurt Page
52b6541dd0 docs: CONTRIBUTING-DE.md convert to UTF8 (#11523) 2025-04-22 08:17:43 +08:00
Too Late (bot)
86d9e62780 Translations update from Toolate (#11510)
* Added translation using Weblate (Russian)

* Translated using Weblate (Russian)

Currently translated at 100.0% (2 of 2 strings)

Translation: RustDesk/metadata
Translate-URL: https://toolate.othing.xyz/projects/rustdesk/metadata/ru/

* Translated using Weblate (Russian)

Currently translated at 100.0% (31 of 31 strings)

Translation: RustDesk/MSI Package
Translate-URL: https://toolate.othing.xyz/projects/rustdesk/msi-package/ru/

---------

Co-authored-by: Yurt Page <yurtpage+translate@gmail.com>
2025-04-21 10:03:41 +08:00
Yurt Page
a8c822ee5d fastlane: short_description.txt shorten to fit 80 chars limit (#11509) 2025-04-21 09:13:49 +08:00
fufesou
bc1f629c17 fix: ci (#11504)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-04-19 21:24:44 +08:00
RustDesk
66a9882e30 22.04 runner 2025-04-18 22:34:10 +08:00
RustDesk
978ead4c42 22.04 runner 2025-04-18 22:33:44 +08:00
summoner001
56010344b7 Update hu.rs (#11498)
* Update hu.rs

Translate new strings
Fixing sentences

* Update hu.rs

Fix the translation of TCP-tunneling word

* Update hu.rs

fix placeholders
2025-04-18 22:26:51 +08:00
Dominik
c853dd4279 Update flutter-build.yml (#11492) 2025-04-18 22:26:19 +08:00
rustdesk
f1f504f9f1 OPTION_ENABLE_REMOTE_PRINTER 2025-04-18 11:32:51 +08:00
Miguel Gomez
f34f962b73 adding missing --recurse-submodule in the Build section of the README. Should be present to ensure no issues arise for hbb_common (#11475) 2025-04-17 19:00:28 +08:00
Y-Ploni
ded19ce5b9 Update he.rs (#11460) 2025-04-15 17:12:32 +08:00
rustdesk
3f9ba53dca fix ci 2025-04-14 12:02:08 +08:00
rustdesk
3e82b99f8e fix ci 2025-04-14 11:46:33 +08:00
rustdesk
98e9e2a0e8 fix ci new flexi_logger failed on rustc 1.75 2025-04-14 11:40:41 +08:00
rustdesk
375cede605 fix ci 2025-04-13 23:53:06 +08:00
rustdesk
838decccc4 tokio 1.44 2025-04-13 23:46:34 +08:00
flusheDData
b7742ff806 New terms (#11412)
* Update es.rs

* Update es.rs

---------

Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2025-04-13 17:51:12 +08:00
fufesou
36815e9a02 fix: build macos (#11448)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-04-12 12:39:05 +08:00
Alex Rijckaert
581313341b Update nl.rs (#11375) 2025-04-11 18:36:11 +08:00
Giorgi
d9109560a7 Revert "RustDesk Georgian (ქართული) Localization" (#11418)
* Create GE.rs

Georgian Language

* Update lang.rs

adding Georgian Language

* Rename GE.rs to ge.rs

* Finalizing translate

* Update ge.rs

fix(lang/ge.rs): remove accidental  header paste

* Update ge.rs

fix(lang/ge.rs): remove  paste

* Update ge.rs
2025-04-10 01:19:53 +08:00
RustDesk
d7dc49f1f7 Revert "RustDesk Georgian (ქართული) Localization (#11362)" (#11413)
This reverts commit f9af3e3a0c.
2025-04-09 23:58:03 +08:00
Giorgi
f9af3e3a0c RustDesk Georgian (ქართული) Localization (#11362)
* Create GE.rs

Georgian Language

* Update lang.rs

adding Georgian Language

* Rename GE.rs to ge.rs

* Finalizing translate
2025-04-09 22:34:13 +08:00
Andrzej Rudnik
3b73ee3a23 Update pl.rs - remote printing (#11360)
Translation updated to version 1.3.9.
2025-04-08 15:04:47 +08:00
fufesou
d8eb23a571 fix: msi, silent install, launch app tray (#11389)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-04-07 15:40:17 +08:00
Marcos Rodrigo Ladeia
cc0761446f Update ptbr.rs (#11354)
Improvements in translation for better user understanding.
2025-04-07 14:05:14 +08:00
asereze
d972c0eda1 Update sc.rs (#11342)
Some fixes
2025-04-07 14:04:03 +08:00
fufesou
2d403913b5 fix: enigo, macos, F11 (#11371)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-04-06 10:42:15 +08:00
fufesou
62a83ad319 fix: build (#11365)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-04-05 10:00:34 +08:00
fufesou
a7aacc7855 refact: win, dlopen mf (#11353)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-04-05 08:45:33 +08:00
fufesou
9ddeab9be2 fix: vcpkg, cmake, compatibility 3.5 (#11356)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-04-05 08:45:01 +08:00
Marcos Rodrigo Ladeia
d808bb2947 Update Portuguese (Brazil) Translations (#11322)
* Update ptbr.rs

* Update ptbr.rs "web_id_input_tip"
2025-04-03 15:16:00 +08:00
XLion
c19f33a137 Update tw.rs (#11325) 2025-04-02 17:12:10 +08:00
asereze
11d3ea5f24 Update sc.rs (#11309) 2025-04-01 21:57:27 +08:00
solokot
ca1b35440b Update ru.rs (#11306) 2025-04-01 21:57:12 +08:00
Kleofass
3dbe27ea57 Update lv.rs (#11298) 2025-03-31 13:46:38 +08:00
Mahdi Rahimi
a2725df7cd Update Arabic translation in ar.rs (#11281) 2025-03-31 13:46:25 +08:00
Mahdi Rahimi
f32988b454 Updated Persian translations in fa.rs (#11280) 2025-03-31 13:46:15 +08:00
bovirus
adf83a1b25 Italian language update (#11278) 2025-03-31 13:45:59 +08:00
Mr-Update
ea74ed12b8 Update de.rs (#11269) 2025-03-30 14:45:17 +08:00
Lynilia
5f3b980373 Update fr.rs (#11266) 2025-03-29 21:55:28 +08:00
fufesou
23e70c0fd1 refact: remote printer, adapter dll, free data ptr (#11279)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-03-28 21:58:46 +08:00
fufesou
4b14f86134 refact: remote printer, log (#11271)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-03-28 10:56:19 +08:00
fufesou
ee2478168c fix: remote printer (#11270)
* fix: remote printer, log

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

* fix: remote printer, avoid double sign

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

* Spawn a new thread to handle the print job.

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2025-03-28 10:36:42 +08:00
fufesou
f4bbf82363 feat: remote printer (#11231)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-03-27 15:34:27 +08:00
Kleofass
1cb53c1f7a Update lv.rs (#11250) 2025-03-27 14:42:31 +08:00
RustDesk
eea9e0fa43 Update README-DE.md (#11247) 2025-03-26 15:23:40 +08:00
RustDesk
ac630c2ca6 Update README-ZH.md 2025-03-25 15:41:36 +08:00
RustDesk
9831f93430 Update README.md 2025-03-24 21:59:08 +08:00
Lynilia
c074a1d6af Update fr.rs (#11184) 2025-03-20 15:12:03 +08:00
asereze
47c93f8544 Update sc.rs (#11176)
* Update sc.rs

* Update sc.rs
2025-03-19 22:26:14 +08:00
rustdesk
c06ac9341a improve check_software_update 2025-03-18 15:12:41 +08:00
Alex Rijckaert
8d231b4605 Update nl.rs (#11172) 2025-03-18 14:48:48 +08:00
Alex Rijckaert
745ba1673d Update nl.rs (#11155) 2025-03-17 22:04:18 +08:00
solokot
2ef1dd99de Update ru.rs (#11132) 2025-03-16 15:11:18 +08:00
XLion
960d9a042f Update tw.rs (#11126) 2025-03-15 21:37:39 +08:00
bovirus
10457dfe45 Italian language update (#11123) 2025-03-14 17:14:05 +08:00
21pages
971d4e6976 ipc example for test (#11127)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-03-14 00:21:05 +08:00
Mr-Update
2dbff45588 Update de.rs (#11106)
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2025-03-13 09:36:27 +08:00
flusheDData
2bdb621417 Update es.rs (#11111)
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2025-03-13 09:36:00 +08:00
Alex Rijckaert
47b00054d2 Update nl.rs (#11102)
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2025-03-13 09:35:21 +08:00
21pages
d1c8b331c5 Option allow-d3d-render and fix ios ci (#11107)
* option `allow-d3d-render`, default false

Add this option because it fails on some machines

Signed-off-by: 21pages <sunboeasy@gmail.com>

* only add nokhwa to windows and linux dependencies

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-03-13 09:34:13 +08:00
fufesou
1403c939db fix: msi, silent install, do not launch app (#11115)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-03-13 09:33:30 +08:00
rustdesk
f1d2073d43 revert back, because useless 2025-03-12 20:06:35 +08:00
rustdesk
f7c930e153 fix https://github.com/rustdesk/rustdesk/discussions/11104 2025-03-12 19:07:25 +08:00
bovirus
22005bac75 Italian language update (#11088) 2025-03-12 15:14:47 +08:00
XLion
8f7bb5a032 Update tw.rs (#11087) 2025-03-12 15:14:21 +08:00
21pages
e0fd698101 opt dropdown button of connection page (#11086)
* Use menu style of the peer card
* Add margin between connection button and dropdown button
* Use thinner icon

Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-03-11 16:29:02 +08:00
21pages
b2cc9eac23 set rgba_data.valid to false when open a new single display on the old session (#11078)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-03-10 21:12:13 +08:00
Naveenkumar
5f521c80a7 Create ta.rs (#11068)
* Create ta.rs

* Update lang.rs
2025-03-10 21:07:15 +08:00
21pages
f0f999dc27 view camera (#11040)
* view camera

Signed-off-by: 21pages <sunboeasy@gmail.com>

* `No cameras` prompt if no cameras available,  `peerGetSessionsCount` use
connType as parameter

Signed-off-by: 21pages <sunboeasy@gmail.com>

* fix, use video_service_name rather than display_idx as key in qos,etc

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
Co-authored-by: Adwin White <adwinw01@gmail.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2025-03-10 21:06:53 +08:00
fufesou
df4a101316 fix: build macos, default feature (#11075)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-03-10 10:16:17 +08:00
rustdesk
bdc53f0190 improve lock, https://github.com/rustdesk/rustdesk/issues/11067 2025-03-10 11:10:09 +09:00
Madis Otenurm
cef4175961 Update et.rs (#11054)
* Update et.rs

* Update et.rs

Added more missing translations

* Update et.rs

* Update et.rs

* Update et.rs
2025-03-08 17:38:58 +08:00
asereze
4ff75412c3 Update sc.rs (#11046) 2025-03-07 21:24:45 +08:00
dependabot[bot]
f1329ca69e Git submodule: Bump libs/hbb_common from 7cf11f7 to 83419b6 (#11042)
Bumps [libs/hbb_common](https://github.com/rustdesk/hbb_common) from `7cf11f7` to `83419b6`.
- [Commits](7cf11f7b77...83419b6549)

---
updated-dependencies:
- dependency-name: libs/hbb_common
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-07 09:21:40 +08:00
ANB5Dev
c95aaf563e fixed Dutch names for macOS permissions (#11020) 2025-03-06 09:49:44 +08:00
Mani Ka
11fed81c4d Update reference to flutter web UI (#11029)
- the src js web UI has moved to directory v1 in flutter/web/js as v2 is under development . The link in README.md is returning 404
2025-03-06 09:49:25 +08:00
zuiyu
561bc18f49 Fix unused import with dxgiformat (#11032) 2025-03-06 09:49:04 +08:00
Ivan Beà
6946b863f7 Update ca.rs (#11024)
Update catalan localization
2025-03-05 16:14:42 +08:00
Yuni
8f68861920 Update CONTRIBUTING-KR.md (#11016)
* Update CONTRIBUTING-KR.md

Signed-off-by: yeonhee7935 <yeonhee7935@naver.com>

* Update CONTRIBUTING-KR.md

Signed-off-by: yeonhee7935 <yeonhee7935@naver.com>

---------

Signed-off-by: yeonhee7935 <yeonhee7935@naver.com>
2025-03-04 17:37:54 +08:00
21pages
171d178b09 make errorText of DialogTextField selectable (#11013)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-03-04 14:11:18 +08:00
rustdesk
7305b6bd1c https://github.com/rustdesk/rustdesk/discussions/937#discussioncomment-12373814 try to support citrix session 2025-03-03 19:06:01 +08:00
marboroman
6600c8c648 Update ru.rs (#10984)
Changed to the translation which makes sense.
2025-03-03 14:55:32 +08:00
marboroman
32b77f8968 Update ru.rs (#10979)
Made long translation short to fit in user interface.
2025-03-03 14:55:21 +08:00
marboroman
0bda90f8fb Update ru.rs (#10978)
update wrong translation for privacy mode activation
2025-03-03 14:55:11 +08:00
Lynilia
2b68c46fdc French localization rework (#10966) 2025-03-02 18:04:22 +08:00
fufesou
bfbf00f18c fix: custom client, settings button (#10974)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-03-01 19:43:01 +08:00
asereze
e17ab74040 Sardinian translation (#10941)
* Sardinian translation

Sardinian ("Sardu", ISO 639-1 code: "sc") translation.

* Update lang.rs

* Corrected typo
2025-03-01 18:39:58 +08:00
fufesou
41cd375e3c fix: potential memleak (#10955)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-02-28 12:14:40 +08:00
fufesou
0d919157c9 Fix/win build (#10954)
* fix: win build

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

* fix: win, build

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2025-02-28 11:56:17 +08:00
fufesou
00293a9902 Feat/macos clipboard file (#10939)
* feat: macos, clipboard file

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

* Can't reuse file transfer

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

* handle paste task

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2025-02-28 00:46:46 +08:00
rustdesk
bc3a58f6f4 1.3.9 2025-02-26 18:00:31 +08:00
rustdesk
d8496aba0b refactor is_custom_client 2025-02-26 00:32:54 +08:00
rustdesk
280c12942f improve android build 2025-02-25 00:30:29 +08:00
Andrzej Rudnik
3a5b30a5e7 Update pl.rs (#10901) 2025-02-24 23:08:48 +08:00
dependabot[bot]
c46023bbde Git submodule: Bump libs/hbb_common from 16900b9 to 7cf11f7 (#10895)
Bumps [libs/hbb_common](https://github.com/rustdesk/hbb_common) from `16900b9` to `7cf11f7`.
- [Commits](16900b9b06...7cf11f7b77)

---
updated-dependencies:
- dependency-name: libs/hbb_common
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-24 08:58:25 +08:00
Kleofass
93feedc212 Update lv.rs (#10883) 2025-02-23 13:39:43 +08:00
luzpaz
6f1a769741 fix: source typo in flutter/lib/common/widgets/address_book.dart (#10884)
Found via codespell
2025-02-23 09:01:52 +08:00
princeyogesh
e191d11f74 before docker run command added git submoulde update command in docker build Updated README.md (#10878)
there is dependency on submodule libs/hbb_common, 
we need to initialize submodule after cloning repo and before running container
2025-02-22 13:17:11 +08:00
fufesou
fc396d2166 fix: check text editing controlling, if selection is valid (#10868)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-02-21 11:00:19 +08:00
Theofanis Sarmidis
2575e14811 Update el.rs (#10866) 2025-02-21 10:42:12 +08:00
fufesou
0b9a6a280e fix: remote id, update text and reserve selection (#10867)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-02-21 10:41:57 +08:00
fufesou
343f12b380 fix: load local peers, called two times on select tab (#10859)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-02-20 22:47:42 +08:00
fufesou
ce1e4863cb fix: load peers, always push event data (#10856)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-02-20 22:44:18 +08:00
fufesou
f631c1c28d refact: Remote ID editor, only select text on focus (#10854)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-02-20 19:35:04 +08:00
fufesou
8b9a7a3506 refact: optimize, ID search peers (#10853)
* refact: optimize, preload peers

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

* Update dialogs.dart

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2025-02-20 18:31:12 +08:00
fufesou
055b351164 refact: optimize, loading recent peers (#10847)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-02-20 11:53:36 +08:00
fufesou
2e89a33210 fix: android, back function (#10843)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-02-20 01:02:24 +08:00
Alex Rijckaert
965cc6af26 Update nl.rs (#10834) 2025-02-20 00:25:23 +08:00
rustdesk
16e191f913 fix de 2025-02-20 00:24:24 +08:00
fufesou
1d1e79c802 revert, peers card, sort by online status (#10829)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-02-19 14:14:02 +08:00
Mr-Update
9ffe516f54 Update de.rs (#10827) 2025-02-19 08:42:15 +08:00
solokot
ac20d2fb56 Update ru.rs (#10794) 2025-02-19 01:11:36 +08:00
bovirus
2217152216 Italian language update (#10796) 2025-02-19 01:11:22 +08:00
XLion
ee288280b3 Update tw.rs (#10799) 2025-02-19 01:11:08 +08:00
John Fowler
cccdb2f289 Update hu.rs (#10804)
Translate new strings.
Clarification of some translations.
2025-02-19 01:10:52 +08:00
ANB5Dev
1ddab27c0e NL lang further improvements (#10813) 2025-02-19 01:10:41 +08:00
Alex Rijckaert
451b6dc651 Update nl.rs (#10812) 2025-02-19 01:10:32 +08:00
rustdesk
86b327ee41 they always forget to remove :21114 for https, so I remove for them 2025-02-18 16:18:41 +08:00
rustdesk
6e305d4865 improve sysinfo update 2025-02-18 16:09:25 +08:00
21pages
77af6c4ce1 clear selected device group or user when search text changes (#10815)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-02-18 09:08:38 +08:00
21pages
fa49c72835 fix, accessible peers filter considering device group name (#10809)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-02-17 17:36:47 +08:00
rustdesk
c150143d86 device_group_name in devices.py 2025-02-17 16:28:47 +08:00
fufesou
023d46b48c refact: android, handle right click (#10806)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-02-16 20:45:09 +08:00
rustdesk
356adbcd8c more about allow - 2025-02-15 19:00:43 +08:00
rustdesk
33b47dd6e3 allow dash in id 2025-02-15 18:51:30 +08:00
fufesou
a548e9c94d fix: android, controlled side, gesture (#10792)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-02-15 18:33:26 +08:00
21pages
cefda0dec1 device group (#10781)
1. Rename `Group` tab to `Accessible devices`
2. Add accessible device groups at the top of search list
3. option `preset-device-group-name` and command line `--assign --device_group_name`

Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-02-15 12:13:11 +08:00
rustdesk
8f545491a2 verify_login, but not eable yet 2025-02-14 16:39:09 +08:00
rustdesk
263bbfc66f missed clear 2025-02-12 17:04:56 +08:00
fufesou
a039741e5a fix: win10, border (#10753)
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2025-02-10 13:50:28 +08:00
fufesou
2a0e8c109b fix: macos, main window, dark theme, border (#10749)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-02-10 00:25:11 +08:00
rustdesk
9614bf266a update READEME 2025-02-08 16:03:04 +08:00
rustdesk
aa63ebc7e5 Misuse Disclaimer 2025-02-05 15:28:30 +08:00
fufesou
fbba8f0b34 refact: file copy&paste, cross platform (no macOS) (#10671)
* feat: unix, file copy&paste

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

* refact: unix file c&p, check peer version

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

* Update pubspec.yaml

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2025-02-04 20:33:02 +08:00
ANB5Dev
a27fa43081 Update NL translation: spelling, capitalization, missing entries (#10661) 2025-02-03 22:18:20 +08:00
rustdesk
7a5941de98 remove devcontainer since not maintained yet 2025-02-02 20:31:44 +08:00
rustdesk
db3ca6a373 remove useless code 2025-02-01 13:07:27 +08:00
rustdesk
ce5f0d513f 2024 -> 2025 2025-01-31 16:54:57 +08:00
rustdesk
05b0f95b79 restore entrypoint.sh 2025-01-30 13:53:02 +08:00
rustdesk
8b24b195a2 remove useless files 2025-01-30 13:49:37 +08:00
rustdesk
5fc8e8c428 remove PUBLIC_RS_PUB_KE 2025-01-29 16:57:28 +08:00
RustDesk
25f917a7b4 misused by bad guys (#10614) 2025-01-28 16:16:00 +08:00
fufesou
55005f8129 fix: win, file clipboard, try empty (#10609)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-01-27 16:16:44 +08:00
fufesou
f08cb0412d fix: windows, dll, pre-loading attack (#10608)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-01-26 19:39:38 +08:00
XLion
fc2e27bcf0 Create dependabot.yml (#10593) 2025-01-26 14:18:26 +08:00
Theofanis Sarmidis
7aa4592669 Update and fixes el.rs (#10600) 2025-01-25 16:39:16 +08:00
Y-Ploni
d656ae2956 Update he.rs (#10594) 2025-01-24 15:09:36 +08:00
RustDesk
e4f00361f6 Update README.md (#10587) 2025-01-23 13:24:14 +08:00
RustDesk
1b49d49df2 Update README.md (#10586) 2025-01-23 13:23:20 +08:00
bjoernp
80f759c1ed norwegian translation (#10579)
Signed-off-by: bjoernp116 <bjoernpollen@gmail.com>
2025-01-23 13:22:25 +08:00
21pages
da80f3352a fix vaapi create 2 times at first (#10576)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-01-22 20:27:00 +08:00
Vasyl Gello
ec3ba5be8e Fix issues spotted during 1.3.7 fdroid build (#10570)
* bridge.yml: Explicitly install cargo-expand of certain version

@linsui spotted this trying to fix the build failure of 1.3.7
on f-droid:

https://gitlab.com/fdroid/fdroiddata/-/merge_requests/18766

* flutter-build.yml: drop workarounds for flutter 3.13

@fufesou has removed them from build_fdroid.sh in #10040 but
forgot to remove them in main flutter_build.yml. flutter 3.13
is not used anymore, and those who want to build the old version
using flutter 3.13 can happily check out the appropriate commit
from Git history.

* Bump vcpkg baseline to 2025.01.13

@linsui addressed the missing vcpkg-tools.json file inside vcpkg
revision (microsoft side, not rustdesk's!) by updating the vcpkg
baseline.
2025-01-22 09:26:03 +08:00
21pages
d04756ad70 replace self-hosted arm64 linux with ubuntu-22.04-arm (#10555)
https://github.blog/changelog/2025-01-16-linux-arm64-hosted-runners-now-available-for-free-in-public-repositories-public-preview/

Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-01-21 17:09:24 +08:00
21pages
0eba939cd6 fix windows crash (#10562)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-01-21 16:57:07 +08:00
21pages
1f02bc9d3e bump to 1.3.7 (#10548)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-01-20 23:12:00 +08:00
21pages
5fa8c25e65 opt qos (#10459)
* Adjust bitrate and fps based on TestDelay messages.
* Bitrate is adjusted every 3 seconds, fps is adjusted every second and when receiving test lag.
* Latency optimized at high resolutions. However, when the network is poor, the delay when just connecting or sliding static pages is still obvious.

Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-01-20 17:59:36 +08:00
21pages
c44803f5b0 replace hbb_common with submodule (#10543)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-01-20 17:33:41 +08:00
Samuel FORESTIER
4b066b1fba fix(debian): makes postinst/prerm scripts idempotent (#10541)
* fix(debian): makes `postinst` script idempotent

* fix(debian): makes `prerm` script idempotent
2025-01-20 07:59:40 +08:00
fufesou
dd004f1a2d fix: clipboard, client side, update is required on conn (#10464)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-01-17 02:27:20 +08:00
fufesou
222dbf12cd fix: mobile, don't reset canvas on metrics changed (#10463)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-01-15 18:24:50 +08:00
是果宝呐
b5d54debce Fix a translation error (#10500) 2025-01-14 22:16:17 +08:00
flusheDData
08cdf7134d Update es.rs (#10468) 2025-01-10 21:14:59 +08:00
add-uos
be5037bd03 fix: [translations] Add the translation in tw.rs (#10452)
Add the translation in tw.rs

Log: Add the translation in tw.rs
2025-01-08 14:16:16 +08:00
rustdesk
f9915df926 update readme 2025-01-08 00:23:17 +08:00
rustdesk
f96c759cf5 fix https://github.com/rustdesk/rustdesk/issues/10440 2025-01-07 11:52:43 +08:00
Xiaobo Liu
8f329ebc1a scrap: style (#10445) 2025-01-07 11:21:43 +08:00
Xiaobo Liu
4a3c11e711 scrap: fixed build warnning (#10442)
```shell
warning: elided lifetime has a name
   --> src/common/mod.rs:192:21
    |
187 |     pub fn to<'a>(
    |               -- lifetime `'a` declared here
...
192 |     ) -> ResultType<EncodeInput> {
    |                     ^^^^^^^^^^^ this elided lifetime gets resolved as `'a`
    |
    = note: `#[warn(elided_named_lifetimes)]` on by default
```
2025-01-07 11:14:20 +08:00
Xiaobo Liu
0dbd3094ec hbb_common: simplify is_compressed_file (#10436)
* hbb_common: simplify is_compressed_file

Signed-off-by: Xiaobo Liu <cppcoffee@gmail.com>

* `exts` rename to `compressed_exts`

---------

Signed-off-by: Xiaobo Liu <cppcoffee@gmail.com>
2025-01-06 18:20:18 +08:00
21pages
40999c3211 fix ffmpeg videotoolbox wrong log (#10413)
* Fix ffmpeg videotoolbox wrong log when changing bitrate
* Let qsv support abr, and it's safe for qsv to changing bitrate.

Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-01-02 22:19:30 +08:00
rustdesk
7c2d62237f missed file 2025-01-01 23:11:38 +08:00
rustdesk
ef90ab2bd4 compelete fix https://github.com/rustdesk/rustdesk/discussions/10210
rather than the awful workaround
2025-01-01 23:05:52 +08:00
Dimitris Apostolou
4f3b821883 fix: fix crate vulnerabilities (#10407) 2025-01-01 10:15:57 +08:00
21pages
98b00cdb3d Fix image blur occurring at the moment of changing quality (#10399)
1. Fix this issue occurs on FFmepg qsv, FFmpeg nvenc and SDK mfx, other
   codecs don't have this problem. Clear cache is needed.

Signed-off-by: 21pages <sunboeasy@gmail.com>
2024-12-30 11:51:36 +08:00
rustdesk
8e4127b6a0 remove all stupid canLaunchUrl 2024-12-29 23:43:31 +08:00
21pages
b1f54acf90 fix andriod update button cannot be clicked (#10394)
1. Remove `canLaunchUrl`, which fix the issue
2. Remove `unregisterEventHandler` of `kCheckSoftwareUpdateFinish` when
   connection page dispose, it's registered on main.

Signed-off-by: 21pages <sunboeasy@gmail.com>
2024-12-29 23:37:52 +08:00
rustdesk
39a430f96f upgrade url_launch 2024-12-28 22:03:34 +08:00
Kleofass
a9f2e14091 Update lv.rs (#10381) 2024-12-27 14:47:01 +08:00
Vasyl Gello
77baba3122 Fix missing locked arg in cargo install (#10374)
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
2024-12-26 15:54:46 +08:00
fufesou
1c62a28ef3 fix: build (#10364)
Signed-off-by: fufesou <linlong1266@gmail.com>
2024-12-25 16:36:13 +08:00
fufesou
9ed2499666 fix: file clipboard, init disabled (#10361)
Signed-off-by: fufesou <linlong1266@gmail.com>
2024-12-25 15:18:06 +08:00
XLion
06bc554216 Fix: DEBIAN Control md5sums (#10356)
* Fix: DEBIAN Control md5 sums

* I forgot import
2024-12-25 00:04:34 +08:00
Jernej Simončič
090f5b65ac Update sl.rs (#10346) 2024-12-24 14:15:22 +08:00
Integral
49dabd3533 refactor: replace &PathBuf with &Path to enhance generality (#10332) 2024-12-23 20:28:04 +08:00
RustDesk
7289dbc80f Update flutter-build.yml (#10337) 2024-12-22 11:35:55 +08:00
rustdesk
72f5184ee0 unused 2024-12-22 11:20:38 +08:00
594 changed files with 101792 additions and 32443 deletions

View File

@@ -2,6 +2,8 @@
rustflags = ["-Ctarget-feature=+crt-static"]
[target.i686-pc-windows-msvc]
rustflags = ["-C", "target-feature=+crt-static", "-C", "link-args=/NODEFAULTLIB:MSVCRT"]
[target.aarch64-pc-windows-msvc]
rustflags = ["-Ctarget-feature=+crt-static"]
[target.'cfg(target_os="macos")']
rustflags = [
"-C", "link-args=-sectcreate __CGPreLoginApp __cgpreloginapp /dev/null",

11
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,11 @@
version: 2
updates:
- package-ecosystem: "gitsubmodule"
directory: "/"
target-branch: "master"
schedule:
interval: "daily"
commit-message:
prefix: "Git submodule"
labels:
- "dependencies"

View File

@@ -0,0 +1,140 @@
#!/usr/bin/env bash
# Applies the Flutter 3.44-only source/pubspec changes on the fly, in CI only.
#
# Windows arm64 needs Flutter >= 3.44 (the first stable release shipping an arm64 Dart SDK +
# engine), which renamed DialogTheme/TabBarTheme -> *Data and needs newer extended_text/
# google_fonts. Every other platform is still on Flutter 3.24.5, where the old names/versions
# are required, so these changes are kept OUT of the committed sources and applied here instead.
#
# Used by BOTH the Windows arm64 build (flutter-build.yml) and its dedicated bridge artifact
# (bridge.yml) so they share an identical 3.44 source state -- the generated *.freezed.dart must
# compile against the same Flutter/freezed version the arm64 build resolves.
#
# Remove this script (and commit the changes) once upstream bumps Flutter across the board.
#
# Run from the repository root. sed is used (not a git-apply patch) because the checked-out
# sources are CRLF on the windows-11-arm runner; the substitutions below are anchor-free and
# therefore CRLF-safe.
set -euo pipefail
readonly NO_MATCHES=0
readonly SINGLE_MATCH=1
readonly THEME_MATCHES=2
has_exact_count() {
local -r expected_count="$1"
local -r pattern="$2"
local -r file="$3"
local actual_count
[[ -r "$file" ]] || return 1
actual_count="$(grep -cF "$pattern" "$file" || true)"
[[ "$actual_count" -eq "$expected_count" ]]
}
# The target background-color line must directly follow DialogThemeData in the selected range.
has_dialog_background_in_theme_range() {
local -r start_pattern="$1"
local -r end_pattern="$2"
local -r target_pattern="$3"
local -r file="$4"
awk -v start_pattern="$start_pattern" \
-v end_pattern="$end_pattern" \
-v target_pattern="$target_pattern" '
index($0, start_pattern) {
in_theme = 1
next
}
in_theme && index($0, end_pattern) {
exit
}
in_theme && index($0, "dialogTheme: DialogThemeData(") {
if (getline > 0) {
line = $0
sub(/\r$/, "", line)
sub(/^[[:space:]]+/, "", line)
matched = line == target_pattern
}
exit
}
END {
exit matched ? 0 : 1
}
' "$file"
}
validate_patch_inputs() {
if [[ ! -f flutter/lib/common.dart || ! -r flutter/lib/common.dart ]]; then
echo "Flutter 3.44 source patch input is missing or unreadable: flutter/lib/common.dart" >&2
return 1
fi
if [[ ! -f flutter/pubspec.yaml || ! -r flutter/pubspec.yaml ]]; then
echo "Flutter 3.44 source patch input is missing or unreadable: flutter/pubspec.yaml" >&2
return 1
fi
}
is_complete_patch_state() {
has_exact_count "$THEME_MATCHES" 'dialogTheme: DialogThemeData(' flutter/lib/common.dart &&
has_exact_count "$THEME_MATCHES" 'tabBarTheme: const TabBarThemeData(' flutter/lib/common.dart &&
has_exact_count "$SINGLE_MATCH" 'backgroundColor: Colors.white,' flutter/lib/common.dart &&
has_exact_count "$SINGLE_MATCH" 'backgroundColor: Color(0xFF18191E),' flutter/lib/common.dart &&
has_exact_count "$SINGLE_MATCH" 'extended_text: 15.0.2' flutter/pubspec.yaml &&
has_exact_count "$SINGLE_MATCH" 'google_fonts: ^8.1.0' flutter/pubspec.yaml &&
has_exact_count "$NO_MATCHES" 'dialogTheme: DialogTheme(' flutter/lib/common.dart &&
has_exact_count "$NO_MATCHES" 'tabBarTheme: const TabBarTheme(' flutter/lib/common.dart &&
has_exact_count "$NO_MATCHES" 'extended_text: 14.0.0' flutter/pubspec.yaml &&
has_exact_count "$NO_MATCHES" 'google_fonts: ^6.2.1' flutter/pubspec.yaml &&
has_dialog_background_in_theme_range 'static ThemeData lightTheme = ThemeData(' \
'static ThemeData darkTheme = ThemeData(' 'backgroundColor: Colors.white,' \
flutter/lib/common.dart &&
has_dialog_background_in_theme_range 'static ThemeData darkTheme = ThemeData(' \
'scrollbarTheme: scrollbarThemeDark,' 'backgroundColor: Color(0xFF18191E),' \
flutter/lib/common.dart
}
is_unpatched_state() {
has_exact_count "$THEME_MATCHES" 'dialogTheme: DialogTheme(' flutter/lib/common.dart &&
has_exact_count "$THEME_MATCHES" 'tabBarTheme: const TabBarTheme(' flutter/lib/common.dart &&
has_exact_count "$SINGLE_MATCH" 'extended_text: 14.0.0' flutter/pubspec.yaml &&
has_exact_count "$SINGLE_MATCH" 'google_fonts: ^6.2.1' flutter/pubspec.yaml &&
has_exact_count "$NO_MATCHES" 'dialogTheme: DialogThemeData(' flutter/lib/common.dart &&
has_exact_count "$NO_MATCHES" 'tabBarTheme: const TabBarThemeData(' flutter/lib/common.dart &&
has_exact_count "$NO_MATCHES" 'backgroundColor: Colors.white,' flutter/lib/common.dart &&
has_exact_count "$NO_MATCHES" 'backgroundColor: Color(0xFF18191E),' flutter/lib/common.dart &&
has_exact_count "$NO_MATCHES" 'extended_text: 15.0.2' flutter/pubspec.yaml &&
has_exact_count "$NO_MATCHES" 'google_fonts: ^8.1.0' flutter/pubspec.yaml
}
if ! validate_patch_inputs; then
exit 1
fi
if is_complete_patch_state; then
echo "Flutter 3.44 source patches already applied."
git --no-pager diff -- flutter/lib/common.dart flutter/pubspec.yaml
exit 0
fi
if ! is_unpatched_state; then
echo "Flutter 3.44 source patches are partially applied or their anchors have drifted." >&2
exit 1
fi
# ThemeData API renames (Flutter 3.27+):
sed -i 's/dialogTheme: DialogTheme(/dialogTheme: DialogThemeData(/g' flutter/lib/common.dart
sed -i 's/tabBarTheme: const TabBarTheme(/tabBarTheme: const TabBarThemeData(/g' flutter/lib/common.dart
sed -i '/static ThemeData lightTheme = ThemeData(/,/static ThemeData darkTheme = ThemeData(/s/dialogTheme: DialogThemeData(/dialogTheme: DialogThemeData(\
backgroundColor: Colors.white,/' flutter/lib/common.dart
sed -i '/static ThemeData darkTheme = ThemeData(/,/scrollbarTheme: scrollbarThemeDark,/s/dialogTheme: DialogThemeData(/dialogTheme: DialogThemeData(\
backgroundColor: Color(0xFF18191E),/' flutter/lib/common.dart
# Dependency bumps required by the newer Dart/Flutter:
sed -i 's/extended_text: 14.0.0/extended_text: 15.0.2/' flutter/pubspec.yaml
sed -i 's/google_fonts: \^6.2.1/google_fonts: ^8.1.0/' flutter/pubspec.yaml
# Fail loudly if any expected substitution did not produce the complete state.
if ! is_complete_patch_state; then
echo "Flutter 3.44 source patches did not produce the expected state." >&2
exit 1
fi
git --no-pager diff -- flutter/lib/common.dart flutter/pubspec.yaml

View File

@@ -0,0 +1,51 @@
#!/usr/bin/env bash
# Prepares a web build on Flutter 3.44.x. Companion to
# apply_flutter_3.44_source_patches.sh (which it runs first): the web target
# additionally needs qr_code_scanner's web implementation patched for the
# dart:ui platformViewRegistry removal, and flutter/web/fonts refreshed with
# the font paths the 3.44 engine requests for offline/air-gapped support
# (rustdesk-server-pro#996; see flutter/web/fonts/sync_fonts.py).
#
# Run from the repository root with Flutter 3.44.x on PATH, then build:
# bash .github/patches/apply_flutter_3.44_web_patches.sh
# (cd flutter && flutter build web --release) # or ./web/js/flutter_build.py
#
# Idempotent. To undo the source changes locally:
# git checkout -- flutter/lib/common.dart flutter/pubspec.yaml flutter/pubspec.lock
set -euo pipefail
flutter --version | grep -q "Flutter 3\.44\." || {
echo "Flutter 3.44.x must be on PATH; found:" >&2
flutter --version | grep "^Flutter" >&2 || true
exit 1
}
# Shared 3.44 source/pubspec patches own their complete-state validation.
bash .github/patches/apply_flutter_3.44_source_patches.sh
# Populate the pub cache with the 3.44 dependency resolution.
(cd flutter && flutter pub get)
# qr_code_scanner 1.0.1 (unmaintained) reads platformViewRegistry from
# dart:ui, which Flutter 3.44 removed; point it at dart:ui_web instead. The
# patched file also compiles on Flutter 3.24 (dart:ui_web exists there), so
# mutating the shared pub cache is safe for other local builds.
QR_WEB="${PUB_CACHE:-$HOME/.pub-cache}/hosted/pub.dev/qr_code_scanner-1.0.1/lib/src/web/flutter_qr_web.dart"
if ! grep -qF "dart:ui_web" "$QR_WEB"; then
sed -i.bak "s|import 'dart:ui' as ui;|import 'dart:ui' as ui; import 'dart:ui_web' as ui_web;|" "$QR_WEB"
rm -f "$QR_WEB.bak"
fi
if grep -qF "ui.platformViewRegistry" "$QR_WEB"; then
sed -i.bak "s|ui\.platformViewRegistry|ui_web.platformViewRegistry|g" "$QR_WEB"
rm -f "$QR_WEB.bak"
fi
# Mirror the fonts this engine version requests into flutter/web/fonts.
python3 flutter/web/fonts/sync_fonts.py
# Fail loudly if any expected state is missing:
grep -qF "import 'dart:ui' as ui; import 'dart:ui_web' as ui_web;" "$QR_WEB"
grep -qF "ui_web.platformViewRegistry" "$QR_WEB"
grep -qF 'google_fonts: ^8.1.0' flutter/pubspec.yaml
echo "Flutter 3.44 web patches applied."

View File

@@ -6,7 +6,7 @@ on:
workflow_call:
env:
FLUTTER_VERSION: "3.22.3"
CARGO_EXPAND_VERSION: "1.0.95"
FLUTTER_RUST_BRIDGE_VERSION: "1.80.1"
RUST_VERSION: "1.75" # https://github.com/rustdesk/rustdesk/discussions/7503
@@ -17,14 +17,27 @@ jobs:
fail-fast: false
matrix:
job:
# Default bridge for every platform still on Flutter 3.24.5 (generated with 3.22.3).
- {
target: x86_64-unknown-linux-gnu,
os: ubuntu-20.04,
os: ubuntu-22.04,
extra-build-args: "",
flutter-version: "3.22.3",
artifact-name: "bridge-artifact",
}
# Dedicated bridge for the Windows arm64 build (Flutter 3.44); runs in parallel.
- {
target: x86_64-unknown-linux-gnu,
os: ubuntu-22.04,
extra-build-args: "",
flutter-version: "3.44.8",
artifact-name: "bridge-artifact-flutter-3.44",
}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
submodules: recursive
- name: Install prerequisites
run: |
@@ -37,44 +50,53 @@ jobs:
gcc \
git \
g++ \
libclang-10-dev \
libclang-dev \
libgtk-3-dev \
llvm-10-dev \
llvm-dev \
nasm \
ninja-build \
pkg-config \
wget
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@v1
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
with:
toolchain: ${{ env.RUST_VERSION }}
targets: ${{ matrix.job.target }}
components: "rustfmt"
- uses: Swatinem/rust-cache@v2
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
prefix-key: bridge-${{ matrix.job.os }}
- name: Cache Bridge
id: cache-bridge
uses: actions/cache@v3
uses: actions/cache@6f8efc29b200d32929f49075959781ed54ec270c # v3
with:
path: /tmp/flutter_rust_bridge
key: vcpkg-${{ matrix.job.arch }}
key: bridge-${{ matrix.job.flutter-version }}
- name: Install flutter
uses: subosito/flutter-action@v2
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
with:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
flutter-version: ${{ matrix.job.flutter-version }}
cache: true
- name: Install flutter rust bridge deps
shell: bash
run: |
cargo install cargo-expand --version ${{ env.CARGO_EXPAND_VERSION }} --locked
cargo install flutter_rust_bridge_codegen --version ${{ env.FLUTTER_RUST_BRIDGE_VERSION }} --features "uuid" --locked
pushd flutter && sed -i -e 's/extended_text: 14.0.0/extended_text: 13.0.0/g' pubspec.yaml && flutter pub get && popd
if [[ "${{ matrix.job.flutter-version }}" == "3.22.3" ]]; then
# Default Flutter 3.22.3: extended_text 14 needs a newer Dart, so downgrade for resolution.
sed -i -e 's/extended_text: 14.0.0/extended_text: 13.0.0/g' flutter/pubspec.yaml
else
# Flutter 3.44 bridge for Windows arm64: match that build's source/pubspec state so the
# generated *.freezed.dart compiles against the same Flutter/freezed it resolves.
bash .github/patches/apply_flutter_3.44_source_patches.sh
fi
pushd flutter && flutter pub get && popd
- name: Run flutter rust bridge
run: |
@@ -82,9 +104,9 @@ jobs:
cp ./flutter/macos/Runner/bridge_generated.h ./flutter/ios/Runner/bridge_generated.h
- name: Upload Artifact
uses: actions/upload-artifact@master
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: bridge-artifact
name: ${{ matrix.job.artifact-name }}
path: |
./src/bridge_generated.rs
./src/bridge_generated.io.rs

View File

@@ -4,9 +4,8 @@ env:
# MIN_SUPPORTED_RUST_VERSION: "1.46.0"
# CICD_INTERMEDIATES_DIR: "_cicd-intermediates"
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
# vcpkg version: 2024.11.16
# for multiarch gcc compatibility
VCPKG_COMMIT_ID: "b2cb0da531c2f1f740045bfe7c4dac59f0b2b69c"
VCPKG_COMMIT_ID: "120deac3062162151622ca4860575a33844ba10b"
on:
workflow_dispatch:
@@ -30,13 +29,13 @@ jobs:
# name: Ensure 'cargo fmt' has been run
# runs-on: ubuntu-20.04
# steps:
# - uses: actions-rs/toolchain@v1
# - uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1
# with:
# toolchain: stable
# default: true
# profile: minimal
# components: rustfmt
# - uses: actions/checkout@v3
# - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
# - run: cargo fmt -- --check
# min_version:
@@ -44,22 +43,24 @@ jobs:
# runs-on: ubuntu-20.04
# steps:
# - name: Checkout source code
# uses: actions/checkout@v3
# uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
# with:
# submodules: recursive
# - name: Install rust toolchain (v${{ env.MIN_SUPPORTED_RUST_VERSION }})
# uses: actions-rs/toolchain@v1
# uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1
# with:
# toolchain: ${{ env.MIN_SUPPORTED_RUST_VERSION }}
# default: true
# profile: minimal # minimal component installation (ie, no documentation)
# components: clippy
# - name: Run clippy (on minimum supported rust version to prevent warnings we can't fix)
# uses: actions-rs/cargo@v1
# uses: actions-rs/cargo@844f36862e911db73fe0815f00a4a2602c279505 # v1
# with:
# command: clippy
# args: --locked --all-targets --all-features -- --allow clippy::unknown_clippy_lints
# - name: Run tests
# uses: actions-rs/cargo@v1
# uses: actions-rs/cargo@844f36862e911db73fe0815f00a4a2602c279505 # v1
# with:
# command: test
# args: --locked
@@ -80,18 +81,35 @@ jobs:
# - { target: x86_64-apple-darwin , os: macos-10.15 }
# - { target: x86_64-pc-windows-gnu , os: windows-2022 }
# - { target: x86_64-pc-windows-msvc , os: windows-2022 }
- { target: x86_64-unknown-linux-gnu , os: ubuntu-20.04 }
# - { target: aarch64-pc-windows-msvc , os: windows-11-arm }
- { target: x86_64-unknown-linux-gnu , os: ubuntu-24.04 }
# - { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
steps:
- name: Free Disk Space (Ubuntu)
if: runner.os == 'Linux'
# jlumbroso/free-disk-space@v1.3.1 is used in .github\workflows\flutter-build.yml
# But pinning to a specific version to avoid unexpected issues is preferred.
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1
with:
tool-cache: false
android: true
dotnet: true
haskell: true
large-packages: false
docker-images: true
swap-storage: false
- name: Export GitHub Actions cache environment variables
uses: actions/github-script@v6
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6
with:
script: |
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
submodules: recursive
- name: Install prerequisites
shell: bash
@@ -108,6 +126,7 @@ jobs:
g++ \
libpam0g-dev \
libasound2-dev \
libunwind-dev \
libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-dev \
libgtk-3-dev \
@@ -127,7 +146,7 @@ jobs:
esac
- name: Setup vcpkg with Github Actions binary cache
uses: lukka/run-vcpkg@v11
uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11
with:
vcpkgDirectory: /opt/artifacts/vcpkg
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
@@ -138,7 +157,7 @@ jobs:
shell: bash
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@v1
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
with:
toolchain: stable
targets: ${{ matrix.job.target }}
@@ -154,10 +173,10 @@ jobs:
cargo -V
rustc -V
- uses: Swatinem/rust-cache@v2
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
- name: Build
uses: actions-rs/cargo@v1
uses: actions-rs/cargo@844f36862e911db73fe0815f00a4a2602c279505 # v1
with:
use-cross: ${{ matrix.job.use-cross }}
command: build
@@ -225,7 +244,7 @@ jobs:
echo "CARGO_TEST_OPTIONS=${CARGO_TEST_OPTIONS}" >> $GITHUB_OUTPUT
- name: Run tests
uses: actions-rs/cargo@v1
uses: actions-rs/cargo@844f36862e911db73fe0815f00a4a2602c279505 # v1
with:
use-cross: ${{ matrix.job.use-cross }}
command: test

View File

@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Clear cache
uses: actions/github-script@v7
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with:
script: |
console.log("About to clear")
@@ -30,7 +30,7 @@ jobs:
console.log("Clear completed")
- name: Purge cache # Above seems not clear thouroughly, so add this to double clear
uses: MyAlbum/purge-cache@v2
uses: MyAlbum/purge-cache@881eb5957687193fa612bf74c0042adc78ea5e54 # v2
with:
accessed: true # Purge caches by their last accessed time (default)
created: false # Purge caches by their created time (default)

View File

@@ -31,7 +31,7 @@ jobs:
shell: bash
- name: Publish RustDesk version file
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
with:
prerelease: true
tag_name: "fdroid-version"

File diff suppressed because it is too large Load Diff

View File

@@ -16,9 +16,8 @@ env:
FLUTTER_ELINUX_VERSION: "3.16.9"
TAG_NAME: "nightly"
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
# vcpkg version: 2024.11.16
VCPKG_COMMIT_ID: "b2cb0da531c2f1f740045bfe7c4dac59f0b2b69c"
VERSION: "1.3.6"
VCPKG_COMMIT_ID: "120deac3062162151622ca4860575a33844ba10b"
VERSION: "1.4.9"
NDK_VERSION: "r26d"
#signing keys env variable checks
ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}"
@@ -80,20 +79,21 @@ jobs:
}
steps:
- name: Export GitHub Actions cache environment variables
uses: actions/github-script@v6
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6
with:
script: |
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
- name: Checkout source code
uses: actions/checkout@v3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
with:
ref: ${{ matrix.job.ref }}
submodules: recursive
- name: Import the codesign cert
if: env.MACOS_P12_BASE64 != null
uses: apple-actions/import-codesign-certs@v1
uses: apple-actions/import-codesign-certs@253ddeeac23f2bdad1646faac5c8c2832e800071 # v1
with:
p12-file-base64: ${{ secrets.MACOS_P12_BASE64 }}
p12-password: ${{ secrets.MACOS_P12_PASSWORD }}
@@ -107,7 +107,7 @@ jobs:
- name: Import notarize key
if: env.MACOS_P12_BASE64 != null
uses: timheuer/base64-to-file@v1.2
uses: timheuer/base64-to-file@adaa40c0c581f276132199d4cf60afa07ce60eac # v1.2
with:
# https://gregoryszorc.com/docs/apple-codesign/stable/apple_codesign_rcodesign.html#notarizing-and-stapling
fileName: rustdesk.json
@@ -126,22 +126,22 @@ jobs:
- name: Install build runtime
run: |
brew install llvm create-dmg nasm cmake gcc wget ninja pkg-config
brew install llvm create-dmg nasm pkg-config
- name: Install flutter
uses: subosito/flutter-action@v2
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
with:
channel: "stable"
flutter-version: ${{ matrix.job.flutter }}
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@v1
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
with:
toolchain: ${{ env.RUST_VERSION }}
targets: ${{ matrix.job.target }}
components: "rustfmt"
- uses: Swatinem/rust-cache@v2
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
prefix-key: ${{ matrix.job.os }}
@@ -156,7 +156,7 @@ jobs:
~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart --c-output ./flutter/macos/Runner/bridge_generated.h
- name: Setup vcpkg with Github Actions binary cache
uses: lukka/run-vcpkg@v11
uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11
with:
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
@@ -165,7 +165,7 @@ jobs:
$VCPKG_ROOT/vcpkg install --x-install-root="$VCPKG_ROOT/installed"
- name: Restore from cache and install vcpkg
uses: lukka/run-vcpkg@v7
uses: lukka/run-vcpkg@8a5116de2b552d6fc8894e9774aacaf2e5db4823 # v7 2026-05-26
if: false
with:
setupOnly: true
@@ -222,7 +222,7 @@ jobs:
done
- name: Publish DMG package
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
with:
prerelease: true
tag_name: ${{ env.TAG_NAME }}
@@ -241,15 +241,16 @@ jobs:
- {
arch: aarch64,
target: aarch64-linux-android,
os: ubuntu-20.04,
os: ubuntu-22.04,
openssl-arch: android-arm64,
ref: master, # latest
}
steps:
- name: Checkout source code
uses: actions/checkout@v3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
with:
ref: ${{ matrix.job.ref }}
submodules: recursive
- name: Install dependencies
run: |
@@ -265,7 +266,8 @@ jobs:
libayatana-appindicator3-dev\
libasound2-dev \
libc6-dev \
libclang-10-dev \
libclang-dev \
libunwind-dev \
libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-dev \
libgtk-3-dev \
@@ -278,7 +280,7 @@ jobs:
libxcb-xfixes0-dev \
libxdo-dev \
libxfixes-dev \
llvm-10-dev \
llvm-dev \
nasm \
yasm \
ninja-build \
@@ -288,13 +290,13 @@ jobs:
wget
- name: Install flutter
uses: subosito/flutter-action@v2
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
with:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@v1
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
with:
toolchain: ${{ env.RUST_VERSION }}
components: "rustfmt"
@@ -308,14 +310,14 @@ jobs:
pushd flutter ; flutter pub get ; popd
~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart
- uses: nttld/setup-ndk@v1
- uses: nttld/setup-ndk@ed92fe6cadad69be94a966a7ee3271275e62f779 # v1
id: setup-ndk
with:
ndk-version: ${{ env.NDK_VERSION }}
add-to-path: true
- name: Setup vcpkg with Github Actions binary cache
uses: lukka/run-vcpkg@v11
uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11
with:
vcpkgDirectory: /opt/artifacts/vcpkg
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
@@ -393,7 +395,7 @@ jobs:
mkdir -p signed-apk; pushd signed-apk
mv ../rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.apk ./rustdesk-test-${{ matrix.job.ref }}-${{ matrix.job.ndk }}.apk
- uses: r0adkll/sign-android-release@v1
- uses: r0adkll/sign-android-release@349ebdef58775b1e0d8099458af0816dc79b6407 # v1
name: Sign app APK
if: env.ANDROID_SIGNING_KEY != null
id: sign-rustdesk
@@ -408,7 +410,7 @@ jobs:
BUILD_TOOLS_VERSION: "30.0.2"
- name: Publish signed apk package
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
with:
prerelease: true
tag_name: ${{ env.TAG_NAME }}

View File

@@ -39,22 +39,21 @@ jobs:
build_output_dir: RustDeskTempTopMostWindow/WindowInjection/${{ inputs.platform }}/${{ inputs.configuration }}
steps:
- name: Add MSBuild to PATH
uses: microsoft/setup-msbuild@v2
uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # v2
- name: Download the source code
run: |
git clone https://github.com/rustdesk-org/RustDeskTempTopMostWindow RustDeskTempTopMostWindow
# Build. commit 53b548a5398624f7149a382000397993542ad796 is tag v0.3
- name: Build the project
run: |
cd RustDeskTempTopMostWindow && git checkout 53b548a5398624f7149a382000397993542ad796
cd RustDeskTempTopMostWindow && git checkout ecd8d6a139eee76845ea66423fb739af450fda90
msbuild ${{ env.project_path }} -p:Configuration=${{ inputs.configuration }} -p:Platform=${{ inputs.platform }} /p:TargetVersion=${{ inputs.target_version }}
- name: Archive build artifacts
uses: actions/upload-artifact@master
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ inputs.upload-artifact }}
with:
name: topmostwindow-artifacts
name: topmostwindow-artifacts-${{ inputs.platform }}
path: |
./${{ env.build_output_dir }}/WindowInjection.dll

View File

@@ -0,0 +1,71 @@
name: Update webpki-roots
# Weekly refresh of the compiled-in TLS root certificates (the webpki-roots
# crate, a snapshot of the Mozilla root store). Roots are otherwise frozen at
# whatever Cargo.lock pins, so old builds miss newly added CAs and keep
# removed (distrusted) ones. Changes go through a PR on purpose: added or
# removed roots should be reviewed, not silently baked into releases.
#
# Note: PRs created with the default GITHUB_TOKEN do not trigger other
# workflows (GitHub limitation). Close and reopen the PR, or push to its
# branch, to run CI on it.
on:
schedule:
- cron: "0 3 * * 1"
workflow_dispatch:
# A manual dispatch overlapping the weekly run would race it force-pushing
# the same branch; queue instead of overlapping, and never cancel a run
# that may have already pushed.
concurrency:
group: update-webpki-roots
cancel-in-progress: false
jobs:
update:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
env:
BRANCH: auto-update-webpki-roots
steps:
- name: Checkout source code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Update webpki-roots in all lockfiles
id: update
run: |
set -e
git ls-files -z '*Cargo.lock' | while IFS= read -r -d '' lock; do
dir=$(dirname "$lock")
for v in $(sed -n '/name = "webpki-roots"/{n;s/.*version = "\(.*\)"/\1/p;}' "$lock" | sort -u); do
echo "updating webpki-roots@$v in $dir"
(cd "$dir" && cargo update -p "webpki-roots@$v")
done
done
if git diff --quiet -- '*Cargo.lock'; then
echo "changed=0" >> "$GITHUB_OUTPUT"
else
echo "changed=1" >> "$GITHUB_OUTPUT"
git --no-pager diff -- '*Cargo.lock'
fi
- name: Create pull request
if: steps.update.outputs.changed == '1'
env:
GH_TOKEN: ${{ github.token }}
run: |
set -e
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git checkout -B "$BRANCH"
git add -- '*Cargo.lock'
git commit -m "chore: update webpki-roots to latest Mozilla root store"
git push -f origin "$BRANCH"
if [ -z "$(gh pr list --head "$BRANCH" --state open --json number --jq '.[].number')" ]; then
gh pr create \
--title "chore: update webpki-roots to latest Mozilla root store" \
--body "Automated weekly refresh of the compiled-in TLS root certificates (webpki-roots). Please review the added/removed roots. CI does not run automatically on PRs created by GITHUB_TOKEN; close and reopen this PR to trigger it."
fi

View File

@@ -1,13 +0,0 @@
name: Publish to WinGet
on:
release:
types: [released]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: vedantmgoyal9/winget-releaser@main
with:
identifier: RustDesk.RustDesk
version: ${{ github.event.release.tag_name }}
token: ${{ secrets.WINGET_TOKEN }}

5
.gitignore vendored
View File

@@ -3,6 +3,7 @@
.vscode
.idea
.DS_Store
.env
libsciter-gtk.so
src/ui/inline.rs
extractor
@@ -54,4 +55,6 @@ examples/**/target/
vcpkg_installed
flutter/lib/generated_plugin_registrant.dart
libsciter.dylib
flutter/web/
flutter/web/
# libdrmtap is cloned at build time by build.py (not a submodule)
/third_party/libdrmtap/

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "libs/hbb_common"]
path = libs/hbb_common
url = https://github.com/rustdesk/hbb_common

105
AGENTS.md Normal file
View File

@@ -0,0 +1,105 @@
# RustDesk Guide
## Project Layout
### Directory Structure
* `src/` Rust app
* `src/server/` audio / clipboard / input / video / network
* `src/platform/` platform-specific code
* `src/ui/` legacy Sciter UI (deprecated)
* `flutter/` current UI
* `libs/hbb_common/` config / proto / shared utils
* `libs/scrap/` screen capture
* `libs/enigo/` input control
* `libs/clipboard/` clipboard
* `libs/hbb_common/src/config.rs` all options
### Key Components
- **Remote Desktop Protocol**: Custom protocol implemented in `src/rendezvous_mediator.rs` for communicating with rustdesk-server
- **Screen Capture**: Platform-specific screen capture in `libs/scrap/`
- **Input Handling**: Cross-platform input simulation in `libs/enigo/`
- **Audio/Video Services**: Real-time audio/video streaming in `src/server/`
- **File Transfer**: Secure file transfer implementation in `libs/hbb_common/`
### UI Architecture
- **Legacy UI**: Sciter-based (deprecated) - files in `src/ui/`
- **Modern UI**: Flutter-based - files in `flutter/`
- Desktop: `flutter/lib/desktop/`
- Mobile: `flutter/lib/mobile/`
- Shared: `flutter/lib/common/` and `flutter/lib/models/`
## Rust Rules
* Avoid `unwrap()` / `expect()` in production code.
* Exceptions:
* tests;
* lock acquisition where failure means poisoning, not normal control flow.
* Otherwise prefer `Result` + `?` or explicit handling.
* Do not ignore errors silently.
* Avoid unnecessary `.clone()`.
* Prefer borrowing when practical.
* Do not add dependencies unless needed.
* Keep code simple and idiomatic.
## Tokio Rules
* Assume a Tokio runtime already exists.
* Never create nested runtimes.
* Never call `Runtime::block_on()` inside Tokio / async code.
* Do not hide runtime creation inside helpers or libraries.
* Do not hold locks across `.await`.
* Prefer `.await`, `tokio::spawn`, channels.
* Use `spawn_blocking` or dedicated threads for blocking work.
* Do not use `std::thread::sleep()` in async code.
## Editing Hygiene
* Change only what is required.
* Prefer the smallest valid diff.
* Do not refactor unrelated code.
* Do not make formatting-only changes.
* Keep naming/style consistent with nearby code.
### Comments
* Keep them short: one line by default, three at most.
* Say **why**, never what. If the code already says it, delete the comment.
* A comment must never be longer than the code it describes.
* Applies to YAML, shell and Python too, not just Rust.
### Be minimally invasive
* Prefer purely additive changes: layer new (`#[cfg]`-gated) blocks or new functions around existing code instead of restructuring it. The ideal diff for a fix adds lines and modifies/deletes none.
* Do not extract or reshape existing code just to enable your new code; look for a mechanism that leaves existing lines untouched (e.g. hide/show an existing object instead of refactoring its construction into a helper for rebuilding).
* Put new logic in self-contained functions in the module it belongs to (platform-specific logic in `src/platform/`, with `use` inside the function body to avoid churning shared import blocks). Call sites in shared files (`src/tray.rs`, `src/core_main.rs`, `src/server/connection.rs`, …) should be thin one-line hooks.
## Localization (`src/lang/*.rs`)
Each file is a `HashMap<key, translation>`. Layout:
* `template.rs` is the master list of every key. **Never edit it** as part of translation work.
* `en.rs` holds only the keys whose English display text differs from the key itself.
* Every other file (`de.rs`, `fr.rs`, …) carries the full key set; an untranslated entry has an empty value: `("key", "")`.
### Finding the English source for a key
When filling an empty entry, determine the source English text with this rule:
* If `key` exists in `en.rs` **with a non-empty value**, that value is the source text (look it up in `en.rs`).
* Otherwise the **key string itself is the source text** (the key is already plain English).
Then translate that source into the file's target language (infer the language from the file's existing non-empty entries / filename).
### Translation hygiene
* Only fill empty values. Never change keys, and never touch existing non-empty translations.
* Preserve placeholders (`{}`) and escape sequences (`\n`, `\"`) exactly as in the source.
* Do not translate brand or technical tokens: `RustDesk`, `Socks5`, `TLS`, `UAC`, `Wayland`, `X11`, `TCP`, `UDP`, `2FA`, `RDP`, `D3D`, etc.
* Copy URL values (e.g. `doc_*` keys) verbatim from `en.rs`.
### Adding new keys (feature work)
* New English-text keys use sentence case, not Title Case: `Use ID whitelisting`, **not** `Use ID Whitelisting`. Acronyms (ID, IP, 2FA…) stay uppercase. Legacy Title-Case keys (e.g. `Use IP Whitelisting`) stay as-is — do not rename them.
* Since the key itself is the English display text, a sentence-case key usually needs **no** `en.rs` entry; add one only when the display text must differ from the key (e.g. `*_tip` keys).
* Append each new key to `template.rs` (with `""`) and to every `src/lang/*.rs` file (translated, or `""` if unsure), at the end of the list.

1
CLAUDE.md Normal file
View File

@@ -0,0 +1 @@
AGENTS.md

4486
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package]
name = "rustdesk"
version = "1.3.6"
version = "1.4.9"
authors = ["rustdesk <info@rustdesk.com>"]
edition = "2021"
build= "build.rs"
@@ -16,9 +16,12 @@ crate-type = ["cdylib", "staticlib", "rlib"]
name = "naming"
path = "src/naming.rs"
[[bin]]
name = "service"
path = "src/service.rs"
[features]
inline = []
cli = []
use_samplerate = ["samplerate"]
use_rubato = ["rubato"]
use_dasp = ["dasp"]
@@ -27,6 +30,13 @@ default = ["use_dasp"]
hwcodec = ["scrap/hwcodec"]
vram = ["scrap/vram"]
mediacodec = ["scrap/mediacodec"]
drm = ["scrap/drm"]
# The display wake, as its OWN compile gate on top of `drm`. Everything else in the drm backend
# READS (it captures a scanout); the wake WRITES, injecting one synthetic pointer event from the
# root service so a compositor that idle-disabled its outputs re-enables them. That is a different
# kind of operation and deserves a switch that can remove it from the binary entirely, without
# giving up DRM capture: `--features drm` builds the capture path with no wake code compiled in.
drm-wake = ["drm"]
plugin_framework = []
linux-pkg-config = ["magnum-opus/linux-pkg-config", "scrap/linux-pkg-config"]
unix-file-copy-paste = [
@@ -42,7 +52,6 @@ screencapturekit = ["cpal/screencapturekit"]
[dependencies]
async-trait = "0.1"
whoami = "1.5.0"
scrap = { path = "libs/scrap", features = ["wayland"] }
hbb_common = { path = "libs/hbb_common" }
serde_derive = "1.0"
@@ -59,8 +68,6 @@ dasp = { version = "0.11", features = ["signal", "interpolate-linear", "interpol
rubato = { version = "0.12", optional = true }
samplerate = { version = "0.2", optional = true }
uuid = { version = "1.3", features = ["v4"] }
clap = "4.2"
rpassword = "7.2"
num_cpus = "1.15"
bytes = { version = "1.4", features = ["serde"] }
default-net = "0.14"
@@ -73,11 +80,13 @@ crossbeam-queue = "0.3"
hex = "0.4"
chrono = "0.4"
cidr-utils = "0.5"
libloading = "0.8"
fon = "0.6"
zip = "0.6"
shutdown_hooks = "0.1"
totp-rs = { version = "5.4", default-features = false, features = ["gen_secret", "otpauth"] }
stunclient = "0.4"
kcp-sys= { git = "https://github.com/rustdesk-org/kcp-sys"}
reqwest = { version = "0.12", features = ["blocking", "socks", "json", "native-tls", "rustls-tls", "rustls-tls-native-roots", "gzip", "zstd"], default-features=false }
[target.'cfg(not(target_os = "linux"))'.dependencies]
# https://github.com/rustdesk/rustdesk/discussions/10197, not use cpal on linux
@@ -91,9 +100,10 @@ sys-locale = "0.3"
enigo = { path = "libs/enigo", features = [ "with_serde" ] }
clipboard = { path = "libs/clipboard" }
ctrlc = "3.2"
# arboard = { version = "3.4.0", features = ["wayland-data-control"] }
# arboard = { version = "3.4", features = ["wayland-data-control"] }
arboard = { git = "https://github.com/rustdesk-org/arboard", features = ["wayland-data-control"] }
clipboard-master = { git = "https://github.com/rustdesk-org/clipboard-master" }
portable-pty = { git = "https://github.com/rustdesk-org/wezterm", branch = "rustdesk/pty_based_0.8.1", package = "portable-pty" }
system_shutdown = "4.0"
qrcode-generator = "4.1"
@@ -112,14 +122,35 @@ winapi = { version = "0.3", features = [
"cguid",
"cfgmgr32",
"ioapiset",
"winspool",
] }
windows = { version = "0.61", features = [
"Win32",
"Win32_Foundation",
"Win32_Security",
"Win32_Security_Authorization",
"Win32_Storage_FileSystem",
"Win32_System",
"Win32_System_Com",
"Win32_System_Diagnostics",
"Win32_System_Diagnostics_ToolHelp",
"Win32_System_Environment",
"Win32_System_IO",
"Win32_System_Memory",
"Win32_System_Pipes",
"Win32_System_Registry",
"Win32_System_SystemInformation",
"Win32_System_Threading",
"Win32_UI_Shell",
"Win32_UI_WindowsAndMessaging",
] }
winreg = "0.11"
windows-service = "0.6"
virtual_display = { path = "libs/virtual_display" }
remote_printer = { path = "libs/remote_printer" }
impersonate_system = { git = "https://github.com/rustdesk-org/impersonate-system" }
shared_memory = "0.12"
tauri-winrt-notification = "0.1.2"
runas = "1.2"
tauri-winrt-notification = "0.1"
[target.'cfg(target_os = "macos")'.dependencies]
objc = "0.2"
@@ -130,9 +161,13 @@ core-graphics = "0.22"
include_dir = "0.7"
fruitbasket = "0.10"
objc_id = "0.1"
# If we use piet "0.7" here, we must also update core-graphics to "0.24".
piet = "0.6"
piet-coregraphics = "0.6"
foreign-types = "0.3"
[target.'cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))'.dependencies]
tray-icon = { git = "https://github.com/tauri-apps/tray-icon" }
tray-icon = { git = "https://github.com/tauri-apps/tray-icon", version = "0.21.3" }
tao = { git = "https://github.com/rustdesk-org/tao", branch = "dev" }
image = "0.24"
@@ -141,15 +176,14 @@ keepawake = { git = "https://github.com/rustdesk-org/keepawake-rs" }
[target.'cfg(any(target_os = "windows", target_os = "linux"))'.dependencies]
wallpaper = { git = "https://github.com/rustdesk-org/wallpaper.rs" }
[target.'cfg(any(target_os = "macos", target_os = "windows"))'.dependencies]
# https://github.com/rustdesk/rustdesk-server-pro/issues/189, using native-tls for better tls support
reqwest = { git = "https://github.com/rustdesk-org/reqwest", features = ["blocking", "socks", "json", "native-tls", "gzip"], default-features=false }
[target.'cfg(not(any(target_os = "macos", target_os = "windows")))'.dependencies]
reqwest = { git = "https://github.com/rustdesk-org/reqwest", features = ["blocking", "socks", "json", "rustls-tls", "rustls-tls-native-roots", "gzip"], default-features=false }
tiny-skia = "0.11"
softbuffer = "0.4"
fontdb = "0.23"
bytemuck = "1.23"
ttf-parser = "0.25"
[target.'cfg(target_os = "linux")'.dependencies]
libxdo-sys = "0.11"
psimple = { package = "libpulse-simple-binding", version = "2.27" }
pulse = { package = "libpulse-binding", version = "2.27" }
rust-pulsectl = { git = "https://github.com/rustdesk-org/pulsectl" }
@@ -158,7 +192,6 @@ evdev = { git="https://github.com/rustdesk-org/evdev" }
dbus = "0.9"
dbus-crossroads = "0.5"
pam = { git="https://github.com/rustdesk-org/pam" }
users = { version = "0.11" }
x11-clipboard = {git="https://github.com/clslaid/x11-clipboard", branch = "feat/store-batch", optional = true}
x11rb = {version = "0.12", features = ["all-extensions"], optional = true}
percent-encoding = {version = "2.3", optional = true}
@@ -166,6 +199,11 @@ once_cell = {version = "1.18", optional = true}
nix = { version = "0.29", features = ["term", "process"]}
gtk = "0.18"
termios = "0.3"
terminfo = "0.8"
winit = "0.30"
[target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies]
openssl = { version = "0.10", features = ["vendored"] }
[target.'cfg(target_os = "android")'.dependencies]
android_logger = "0.13"
@@ -173,11 +211,16 @@ jni = "0.21"
android-wakelock = { git = "https://github.com/rustdesk-org/android-wakelock" }
[workspace]
members = ["libs/scrap", "libs/hbb_common", "libs/enigo", "libs/clipboard", "libs/virtual_display", "libs/virtual_display/dylib", "libs/portable"]
members = ["libs/scrap", "libs/hbb_common", "libs/enigo", "libs/clipboard", "libs/virtual_display", "libs/virtual_display/dylib", "libs/portable", "libs/remote_printer"]
exclude = ["vdi/host", "examples/custom_plugin"]
# Patch libxdo-sys to use a stub implementation that doesn't require libxdo
# This allows building and running on systems without libxdo installed (e.g., Wayland-only)
[patch.crates-io]
libxdo-sys = { path = "libs/libxdo-sys-stub" }
[package.metadata.winres]
LegalCopyright = "Copyright © 2024 Purslane Ltd. All rights reserved."
LegalCopyright = "Copyright © 2026 Purslane Tech Pte. Ltd. All rights reserved."
ProductName = "RustDesk"
FileDescription = "RustDesk Remote Desktop"
OriginalFilename = "rustdesk.exe"
@@ -193,6 +236,7 @@ os-version = "0.2"
[dev-dependencies]
hound = "3.5"
docopt = "1.1"
[package.metadata.bundle]
name = "RustDesk"
@@ -210,5 +254,4 @@ strip = true
rpath = true
[profile.dev]
split-debuginfo = '...' # Platform-specific.
#strip = "debuginfo"
debug = 1

1
GEMINI.md Normal file
View File

@@ -0,0 +1 @@
AGENTS.md

View File

@@ -1,19 +1,23 @@
<p align="center">
<img src="res/logo-header.svg" alt="RustDesk - Your remote desktop"><br>
<a href="#public-servers">Servers</a> •
<a href="#raw-steps-to-build">Build</a> •
<a href="#how-to-build-with-docker">Docker</a> •
<a href="#file-structure">Structure</a> •
<a href="#snapshot">Snapshot</a><br>
[<a href="docs/README-UA.md">Українська</a>] | [<a href="docs/README-CS.md">česky</a>] | [<a href="docs/README-ZH.md">中文</a>] | [<a href="docs/README-HU.md">Magyar</a>] | [<a href="docs/README-ES.md">Español</a>] | [<a href="docs/README-FA.md">فارسی</a>] | [<a href="docs/README-FR.md">Français</a>] | [<a href="docs/README-DE.md">Deutsch</a>] | [<a href="docs/README-PL.md">Polski</a>] | [<a href="docs/README-ID.md">Indonesian</a>] | [<a href="docs/README-FI.md">Suomi</a>] | [<a href="docs/README-ML.md">മലയാളം</a>] | [<a href="docs/README-JP.md">日本語</a>] | [<a href="docs/README-NL.md">Nederlands</a>] | [<a href="docs/README-IT.md">Italiano</a>] | [<a href="docs/README-RU.md">Русский</a>] | [<a href="docs/README-PTBR.md">Português (Brasil)</a>] | [<a href="docs/README-EO.md">Esperanto</a>] | [<a href="docs/README-KR.md">한국어</a>] | [<a href="docs/README-AR.md">العربي</a>] | [<a href="docs/README-VN.md">Tiếng Việt</a>] | [<a href="docs/README-DA.md">Dansk</a>] | [<a href="docs/README-GR.md">Ελληνικά</a>] | [<a href="docs/README-TR.md">Türkçe</a>]<br>
[<a href="docs/README-UA.md">Українська</a>] | [<a href="docs/README-CS.md">česky</a>] | [<a href="docs/README-ZH.md">中文</a>] | [<a href="docs/README-HU.md">Magyar</a>] | [<a href="docs/README-ES.md">Español</a>] | [<a href="docs/README-FA.md">فارسی</a>] | [<a href="docs/README-FR.md">Français</a>] | [<a href="docs/README-DE.md">Deutsch</a>] | [<a href="docs/README-PL.md">Polski</a>] | [<a href="docs/README-ID.md">Indonesian</a>] | [<a href="docs/README-FI.md">Suomi</a>] | [<a href="docs/README-ML.md">മലയാളം</a>] | [<a href="docs/README-JP.md">日本語</a>] | [<a href="docs/README-NL.md">Nederlands</a>] | [<a href="docs/README-IT.md">Italiano</a>] | [<a href="docs/README-RU.md">Русский</a>] | [<a href="docs/README-PTBR.md">Português (Brasil)</a>] | [<a href="docs/README-EO.md">Esperanto</a>] | [<a href="docs/README-KR.md">한국어</a>] | [<a href="docs/README-AR.md">العربي</a>] | [<a href="docs/README-VN.md">Tiếng Việt</a>] | [<a href="docs/README-DA.md">Dansk</a>] | [<a href="docs/README-GR.md">Ελληνικά</a>] | [<a href="docs/README-TR.md">Türkçe</a>] | [<a href="docs/README-NO.md">Norsk</a>] | [<a href="docs/README-RO.md">Română</a>]<br>
<b>We need your help to translate this README, <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> and <a href="https://github.com/rustdesk/doc.rustdesk.com">RustDesk Doc</a> to your native language</b>
</p>
Chat with us: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
> [!Caution]
> **Misuse Disclaimer:** <br>
> The developers of RustDesk do not condone or support any unethical or illegal use of this software. Misuse, such as unauthorized access, control or invasion of privacy, is strictly against our guidelines. The authors are not responsible for any misuse of the application.
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
Yet another remote desktop software, written in Rust. Works out of the box, no configuration required. You have full control of your data, with no concerns about security. You can use our rendezvous/relay server, [set up your own](https://rustdesk.com/server), or [write your own rendezvous/relay server](https://github.com/rustdesk/rustdesk-server-demo).
Chat with us: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-Advanced%20Features-blue)](https://rustdesk.com/pricing.html)
Yet another remote desktop solution, written in Rust. Works out of the box with no configuration required. You have full control of your data, with no concerns about security. You can use our rendezvous/relay server, [set up your own](https://rustdesk.com/server), or [write your own rendezvous/relay server](https://github.com/rustdesk/rustdesk-server-demo).
![image](https://user-images.githubusercontent.com/71636191/171661982-430285f0-2e12-4b1d-9957-4a58e375304d.png)
@@ -34,7 +38,7 @@ RustDesk welcomes contribution from everyone. See [CONTRIBUTING.md](docs/CONTRIB
## Dependencies
Desktop versions use Flutter or Sciter (deprecated) for GUI, this tutorial is for Sciter only, since it is easier and more friendly to start. Check out our [CI](https://github.com/rustdesk/rustdesk/blob/master/.github/workflows/flutter-build.yml) for building Flutter version.
Desktop versions use Flutter or Sciter (deprecated) for GUI. This tutorial is for Sciter only, since it is easier and more friendly to start. Check out our [CI](https://github.com/rustdesk/rustdesk/blob/master/.github/workflows/flutter-build.yml) for building the Flutter version.
Please download Sciter dynamic library yourself.
@@ -42,7 +46,7 @@ Please download Sciter dynamic library yourself.
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
[macOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
## Raw steps to build
## Raw Steps to build
- Prepare your Rust development env and C++ build env
@@ -55,7 +59,7 @@ Please download Sciter dynamic library yourself.
## [Build](https://rustdesk.com/docs/en/dev/build/)
## How to build on Linux
## How to Build on Linux
### Ubuntu 18 (Debian 10)
@@ -113,7 +117,7 @@ cd
```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
git clone https://github.com/rustdesk/rustdesk
git clone --recurse-submodules https://github.com/rustdesk/rustdesk
cd rustdesk
mkdir -p target/debug
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
@@ -128,6 +132,7 @@ Begin by cloning the repository and building the Docker container:
```sh
git clone https://github.com/rustdesk/rustdesk
cd rustdesk
git submodule update --init --recursive
docker build -t "rustdesk-builder" .
```
@@ -149,7 +154,7 @@ Or, if you're running a release executable:
target/release/rustdesk
```
Please ensure that you are running these commands from the root of the RustDesk repository, otherwise the application might not be able to find the required resources. Also note that other cargo subcommands such as `install` or `run` are not currently supported via this method as they would install or run the program inside the container instead of the host.
Please ensure that you run these commands from the root of the RustDesk repository, or the application may not find the required resources. Also note that other cargo subcommands such as `install` or `run` are not currently supported via this method as they would install or run the program inside the container instead of the host.
## File Structure
@@ -163,7 +168,7 @@ Please ensure that you are running these commands from the root of the RustDesk
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Communicate with [rustdesk-server](https://github.com/rustdesk/rustdesk-server), wait for remote direct (TCP hole punching) or relayed connection
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: platform specific code
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: Flutter code for desktop and mobile
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: JavaScript for Flutter web client
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/v1/js)**: JavaScript for Flutter web client
## Screenshots
@@ -175,6 +180,3 @@ Please ensure that you are running these commands from the root of the RustDesk
![TCP Tunneling](https://github.com/rustdesk/rustdesk/assets/28412477/78e8708f-e87e-4570-8373-1360033ea6c5)
## [Public Servers](#public-servers)
RustDesk is supported by a free EU server, graciously provided by [Codext GmbH](https://codext.link/rustdesk?utm_source=github)

View File

@@ -18,7 +18,7 @@ AppDir:
id: rustdesk
name: rustdesk
icon: rustdesk
version: 1.3.6
version: 1.4.9
exec: usr/share/rustdesk/rustdesk
exec_args: $@
apt:
@@ -99,3 +99,4 @@ AppDir:
AppImage:
arch: aarch64
update-information: guess
comp: gzip

View File

@@ -18,7 +18,7 @@ AppDir:
id: rustdesk
name: rustdesk
icon: rustdesk
version: 1.3.6
version: 1.4.9
exec: usr/share/rustdesk/rustdesk
exec_args: $@
apt:
@@ -102,3 +102,4 @@ AppDir:
AppImage:
arch: x86_64
update-information: guess
comp: gzip

572
build.py
View File

@@ -1,14 +1,24 @@
#!/usr/bin/env python3
import os
import glob
import contextlib
import pathlib
import platform
import zipfile
import urllib.request
import shutil
import hashlib
import re
import subprocess
import argparse
import sys
from pathlib import Path
# Captured at import, while cwd is still the repo root: before Python 3.9 the main script's __file__
# stays relative (bpo-20443), so abspath() re-resolves it against the cwd -- and the ubuntu18.04
# packaging container runs 3.6 and chdir's into flutter/ before it reaches the libdrmtap code.
REPO_ROOT = os.path.dirname(os.path.abspath(__file__))
windows = platform.platform().startswith('Windows')
osx = platform.platform().startswith(
@@ -16,7 +26,8 @@ osx = platform.platform().startswith(
hbb_name = 'rustdesk' + ('.exe' if windows else '')
exe_path = 'target/release/' + hbb_name
if windows:
flutter_build_dir = 'build/windows/x64/runner/Release/'
win_arch = 'arm64' if platform.machine().lower() in ('arm64', 'aarch64') else 'x64'
flutter_build_dir = f'build/windows/{win_arch}/runner/Release/'
elif osx:
flutter_build_dir = 'build/macos/Build/Products/Release/'
else:
@@ -128,6 +139,19 @@ def make_parser():
action='store_true',
help='Build with unix file copy paste feature'
)
parser.add_argument(
'--drm',
action='store_true',
help='Linux only: build the DRM/KMS capture backend (bundles libdrmtap.so, '
'dlopen-ed in-process by the root service). Off by default.'
)
parser.add_argument(
'--print-features',
action='store_true',
help='Print the cargo feature list these flags select, and exit without building. For a '
'caller that runs its own cargo line and then packages with --skip-cargo: it can ask '
'for the list rather than repeat it, so the two cannot drift.'
)
parser.add_argument(
'--skip-cargo',
action='store_true',
@@ -171,7 +195,7 @@ def generate_build_script_for_docker():
# flutter_rust_bridge
dart pub global activate ffigen --version 5.0.1
pushd /tmp && git clone https://github.com/SoLongAndThanksForAllThePizza/flutter_rust_bridge --depth=1 && popd
pushd /tmp/flutter_rust_bridge/frb_codegen && cargo install --path . && popd
pushd /tmp/flutter_rust_bridge/frb_codegen && cargo install --path . --locked && popd
pushd flutter && flutter pub get && popd
~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart
# install vcpkg
@@ -270,6 +294,24 @@ def external_resources(flutter, args, res_dir):
shutil.copytree(f, f'{flutter_build_dir_2}{f.stem}')
def linux_packaging_branch():
"""Which packaging path `main()` will take on THIS host.
MUST mirror the elif chain in main() (pacman / yum / zypper / else), and exists so `--drm` can
refuse a branch that is not drm-aware instead of silently producing a stock-named package with
the capture backend compiled in. Only the final `deb` branch reaches `build_flutter_deb`, which
is what bundles libdrmtap, renames the package, adds Conflicts/Provides and asserts the staged
binary really is a drm build.
"""
if os.path.isfile('/usr/bin/pacman'):
return 'pacman'
if os.path.isfile('/usr/bin/yum'):
return 'yum'
if os.path.isfile('/usr/bin/zypper'):
return 'zypper'
return 'deb'
def get_features(args):
features = ['inline'] if not args.flutter else []
if args.hwcodec:
@@ -280,6 +322,30 @@ def get_features(args):
features.append('flutter')
if args.unix_file_copy_paste:
features.append('unix-file-copy-paste')
if args.drm:
# Say so rather than quietly handing back a stock build: the backend is Linux-only, so on
# any other host the flag cannot be honoured and the resulting binary would look like a
# DRM build without being one.
if windows or osx:
raise Exception('--drm is Linux only')
# And only on the deb branch. The other three Linux paths (pacman/yum/zypper) package
# straight from `target/release` without bundling libdrmtap, without the rename, without
# Conflicts/Provides and without assert_staged_binary_is_drm() -- so they would emit a
# package NAMED `rustdesk` carrying the consent-bypass backend and the root-side uinput
# injection. The separate package name is the informed consent this feature rests on, so
# refuse rather than ship a stock-named build of it.
branch = linux_packaging_branch()
if branch != 'deb':
raise Exception(
f'--drm is only supported on the deb packaging path; this host would package via '
f'{branch}, which cannot bundle libdrmtap or name the package distinctly')
features.append('drm')
# The display wake is its own compile gate on top of `drm`, and the unattended package is
# exactly where it belongs: that variant exists to reach a machine nobody is sitting at,
# and a machine whose screen went dark is the case it is for. Dropping `drm-wake` from
# this line builds the same capture backend with no wake code in the binary at all.
# It is ALSO switchable at runtime; see OPTION_ENABLE_DRM_DISPLAY_WAKE.
features.append('drm-wake')
if osx:
if args.screencapturekit:
features.append('screencapturekit')
@@ -298,7 +364,7 @@ Version: %s
Architecture: %s
Maintainer: rustdesk <info@rustdesk.com>
Homepage: https://rustdesk.com
Depends: libgtk-3-0, libxcb-randr0, libxdo3, libxfixes3, libxcb-shape0, libxcb-xfixes0, libasound2, libsystemd0, curl, libva2, libva-drm2, libva-x11-2, libgstreamer-plugins-base1.0-0, libpam0g, gstreamer1.0-pipewire%s
Depends: libgtk-3-0t64 | libgtk-3-0, libxcb-randr0, libxdo3 | libxdo4, libxfixes3, libxcb-shape0, libxcb-xfixes0, libasound2t64 | libasound2, libsystemd0, curl, libva2, libva-drm2, libva-x11-2, libgstreamer-plugins-base1.0-0, libpam0g, gstreamer1.0-pipewire%s
Recommends: libayatana-appindicator3-1
Description: A remote control software.
@@ -314,9 +380,325 @@ def ffi_bindgen_function_refactor():
'sed -i "s/ffi.NativeFunction<ffi.Bool Function(DartPort/ffi.NativeFunction<ffi.Uint8 Function(DartPort/g" flutter/lib/generated_bridge.dart')
# libdrmtap is fetched at build time from the rustdesk-org fork at a pinned
# commit — the same way rustdesk sources its other native build deps (vcpkg,
# flutter_rust_bridge, ...), rather than carrying a git submodule. It is the ONLY
# pin for the drm backend: rustdesk dlopens this .so at runtime and does not depend on
# the libdrmtap-sys crate (whose build.rs would statically link the C tree, a helper and
# libdrm/seccomp/cap). DRMTAP_REPO, DRMTAP_SHA and DRMTAP_PREBUILT_DIR override it for local testing
# or another fork, and each requires DRMTAP_ALLOW_UNPINNED=1 alongside it (see below).
# The commit is fetched directly by sha, so no branch or tag name takes part in the build: see
# build_libdrmtap_so(). This is the SINGLE source of truth for the pin, deliberately not duplicated in
# any workflow, so a bump is one edit here (plus the informational version comment in
# libs/scrap/Cargo.toml). This commit is libdrmtap v0.5.2.
LIBDRMTAP_REPO_PINNED = 'https://github.com/rustdesk-org/libdrmtap'
LIBDRMTAP_SHA_PINNED = '653de8c774bc245eaf960611ca7a136f7a544d21'
LIBDRMTAP_REPO = os.environ.get('DRMTAP_REPO', LIBDRMTAP_REPO_PINNED)
LIBDRMTAP_SHA = os.environ.get('DRMTAP_SHA', LIBDRMTAP_SHA_PINNED)
# Every way of getting a different .so than the pin needs the same explicit opt-in. Otherwise the
# claim this feature rests on -- that the privileged capture library is the reviewed object at
# LIBDRMTAP_SHA_PINNED -- would hold only as long as nobody happened to have one of these set, and a
# build that silently used something else would be indistinguishable from one that did not.
# DRMTAP_PREBUILT_DIR is in the list because it is the widest of the three: it skips both the fetch
# and the sha verification and hands over an object built from nothing this script can see.
DRMTAP_UNPINNED_OK = os.environ.get('DRMTAP_ALLOW_UNPINNED') == '1'
def _prebuilt_dir_is_the_pinned_checkout(prebuilt_dir):
# A .so built from this repo's own third_party/libdrmtap at the pinned sha is the pinned object,
# not an override, so it must not need the opt-in. This is how CI hands the library from a step
# that has meson to a packaging container that does not.
src = os.path.join(REPO_ROOT, 'third_party', 'libdrmtap')
try:
inside = os.path.commonpath([os.path.abspath(prebuilt_dir), src]) == src
except ValueError:
return False
if not inside or not os.path.isdir(os.path.join(src, '.git')):
return False
try:
head = subprocess.check_output(['git', '-C', src, 'rev-parse', 'HEAD']).decode().strip()
except (subprocess.SubprocessError, OSError):
return False
return head == LIBDRMTAP_SHA
def _validate_libdrmtap_pin():
# Called from build_libdrmtap_so(), NOT at import: a stock (non --drm) build must stay
# byte-identical to upstream in behaviour too, and leftover DRMTAP_* variables in the
# environment (or a malformed sha) must not be able to fail a build that never touches
# libdrmtap.
# `or None` so an empty value reads as unset here exactly as it does in build_libdrmtap_so(),
# which tests it for truthiness.
prebuilt = os.environ.get('DRMTAP_PREBUILT_DIR') or None
if prebuilt and _prebuilt_dir_is_the_pinned_checkout(prebuilt):
prebuilt = None
overridden = [
name
for name, value, pinned in (
('DRMTAP_REPO', LIBDRMTAP_REPO, LIBDRMTAP_REPO_PINNED),
('DRMTAP_SHA', LIBDRMTAP_SHA, LIBDRMTAP_SHA_PINNED),
('DRMTAP_PREBUILT_DIR', prebuilt, None),
)
if value != pinned
]
if overridden and not DRMTAP_UNPINNED_OK:
raise Exception(
f'{", ".join(overridden)} would build libdrmtap from something other than the pinned '
f'{LIBDRMTAP_REPO_PINNED} at {LIBDRMTAP_SHA_PINNED}. That is supported for local work and '
'cross-builds, but it has to be deliberate: set DRMTAP_ALLOW_UNPINNED=1 as well.')
if overridden:
print(f'WARNING: libdrmtap is NOT the pinned build ({", ".join(overridden)} set)')
# Both are interpolated into shell commands below, and both are env-overridable, so validate
# their SHAPE before they get there. This is not only about a hostile environment: a truncated
# or abbreviated sha would otherwise reach `git fetch` and fail with something far less obvious
# than saying so here, and an abbreviated one would defeat the point of pinning.
if not re.fullmatch(r'[0-9a-f]{40}', LIBDRMTAP_SHA):
raise Exception(
f'DRMTAP_SHA must be a full 40-character commit sha, got {LIBDRMTAP_SHA!r}')
if not re.fullmatch(r'(https://|git@)[A-Za-z0-9._~:/@-]+', LIBDRMTAP_REPO):
raise Exception(f'DRMTAP_REPO does not look like a git remote url: {LIBDRMTAP_REPO!r}')
def _single_real_so(paths, where):
# Return the one real libdrmtap.so.0.* object among `paths`, failing if there are zero or several.
# glob order is arbitrary, so silently taking [0] could ship a stale or wrong-arch object left
# over from an earlier build; a mismatch should fail the build loudly instead.
real = sorted(p for p in paths if os.path.isfile(p) and not os.path.islink(p))
if len(real) != 1:
raise Exception(
f'expected exactly one real libdrmtap.so.0.* in {where}, found {len(real)}: {real}')
return real[0]
def build_libdrmtap_so():
# Build libdrmtap.so from the rustdesk-org fork, fetched at the pinned LIBDRMTAP_SHA. The
# pivot dlopen-s this .so in-process in the root service (which already holds
# CAP_SYS_ADMIN) — no setcap helper, no privileged child. Only the shared
# library target is built (the source also carries a helper binary we do not
# ship). Returns the path to the built versioned .so (e.g. libdrmtap.so.0.4.x).
_validate_libdrmtap_pin()
# Allow a caller (e.g. CI) to build the .so ahead of time and hand it in via
# DRMTAP_PREBUILT_DIR (must contain the real libdrmtap.so.0.* object).
prebuilt_dir = os.environ.get('DRMTAP_PREBUILT_DIR')
if prebuilt_dir:
# DRMTAP_PREBUILT_DIR explicitly names the artifact source, so honor it strictly: fail
# (rather than silently falling back to a source build) if it holds no single real .so.
prebuilt = glob.glob(os.path.join(prebuilt_dir, 'libdrmtap.so.0.*'))
so = _single_real_so(prebuilt, f'DRMTAP_PREBUILT_DIR={prebuilt_dir}')
# Check the stub case HERE too, not only on the source path below. This is the widest
# override of the three -- no fetch, no sha verification, an object built by something this
# script cannot see -- so it is the likeliest to hand over a CPU-only build, and skipping the
# assertion on exactly this path would leave the check guarding only the case that was
# already trustworthy.
_assert_so_has_egl(so)
return so
# Fetch the pinned source if it is not already present. third_party/libdrmtap is not a submodule
# anymore; it is git-ignored. The commit is fetched BY SHA rather than by cloning a branch:
# `clone --depth 1 --branch main` only ever fetches the tip, so the moment upstream pushes to
# `main` the pinned commit is not in the shallow clone at all and the build fails on an unreachable
# object. Fetching the sha needs no branch name, so it keeps working across every upstream push and
# is immune to a ref being moved or repointed.
src = os.path.join(REPO_ROOT, 'third_party', 'libdrmtap')
if not os.path.exists(os.path.join(src, 'meson.build')):
if os.path.isdir(src):
shutil.rmtree(src)
os.makedirs(src, exist_ok=True)
system2(f'git -C "{src}" init -q')
system2(f'git -C "{src}" remote add origin {LIBDRMTAP_REPO}')
system2(f'git -C "{src}" fetch --depth 1 origin {LIBDRMTAP_SHA}')
system2(f'git -C "{src}" checkout -q FETCH_HEAD')
# Verify the pin whenever the source is a GIT checkout. A fetch by sha cannot resolve to anything
# else, so this now guards the OTHER case: a reused checkout left by an earlier build at a
# different pin, which is what a bump leaves behind. Reject and remove it so the next run re-fetches
# cleanly. A NON-git tree placed here on purpose (a developer building unreleased local libdrmtap
# source) has nothing to verify and is used as-is.
if os.path.isdir(os.path.join(src, '.git')):
got_sha = subprocess.check_output(
['git', '-C', src, 'rev-parse', 'HEAD']).decode().strip()
if got_sha != LIBDRMTAP_SHA:
shutil.rmtree(src, ignore_errors=True)
raise Exception(
f'libdrmtap at {src} is {got_sha}, expected {LIBDRMTAP_SHA} '
f'(stale checkout from a different pin; removed, re-run to re-fetch)')
build_dir = os.path.join(src, 'build-pkg')
if not os.path.exists(os.path.join(build_dir, 'build.ninja')):
system2(f'meson setup "{build_dir}" "{src}" --buildtype=release')
# Build only the shared library, not the bundled helper binary or the static archive. Since
# libdrmtap 0.4.11 the project is `both_libraries` (a version-scripted .so + a static .a), so the
# bare `drmtap` target is ambiguous ("drmtap:shared_library" vs "drmtap:static_library"); ask for
# the shared one explicitly (rustdesk dlopens the .so and never needs the archive).
system2(f'meson compile -C "{build_dir}" drmtap:shared_library')
sos = glob.glob(os.path.join(build_dir, 'libdrmtap.so.0.*'))
# keep the real object (libdrmtap.so.0.4.x), not the .so/.so.0 symlinks or meson's .p dir, and
# require exactly one so a stale object from an earlier build is never silently picked.
so = _single_real_so(sos, f'the libdrmtap meson build dir {build_dir}')
_assert_so_has_egl(so)
return so
def _assert_so_has_egl(so_path):
# libdrmtap treats egl/glesv2 as OPTIONAL dependencies: without their headers and pkg-config
# files, meson silently builds a CPU-only stub. That stub still exports every symbol the loader
# checks for, so nothing downstream notices -- and the split architecture depends entirely on the
# unprivileged side EGL-detiling the scanout it receives. The result is a build where DRM capture
# quietly degrades to PipeWire on every tiled-scanout host, which is most of them.
#
# Assert on the ARTIFACT rather than passing an option that demands it: `-Degl=enabled` exists
# only in libdrmtap past 0.4.15, and checking what was actually produced also catches a stale or
# hand-substituted object, which a build flag cannot.
#
# EGL is reached by lazy dlopen, on purpose, so that the privileged service never links the GPU
# stack. That means there is no DT_NEEDED to look for and an ELF-level check reports "no EGL" on a
# perfectly good library; the dlopen name and an extension symbol are what a CPU-only stub really
# lacks.
try:
with open(so_path, 'rb') as f:
blob = f.read()
except OSError as err:
raise Exception(f'cannot read the built libdrmtap at {so_path}: {err}') from err
missing = [m for m in (b'libEGL.so.1', b'eglCreateImageKHR') if m not in blob]
if missing:
raise Exception(
f'{so_path} looks like a CPU-only libdrmtap stub (missing '
f'{", ".join(m.decode() for m in missing)}): the EGL detile path the split capture '
'depends on is not in it, and DRM capture would silently fall back to PipeWire. '
'Install the EGL development packages and rebuild (Debian/Ubuntu: libegl-dev '
'libgles2-mesa-dev; Arch: mesa libglvnd).')
DRM_PACKAGE_NAME = 'rustdesk-unattended-wayland'
def assert_so_satisfies_the_runtime_abi_gate(so_path):
"""The .so we are about to ship must be one the RUNTIME will actually accept.
`abi_accepted` in libs/scrap/src/common/drmtap_dl.rs is the only place the pinned library's
version is ever validated, and it runs at dlopen time on the USER's machine. Nothing in the
build or in CI compared the two, so the pin and the gate could drift apart and every existing
assertion would still pass: the EGL check does not look at the version, the CI symbol contract
does not call drmtap_version(), and the deb-contents regex matches any `libdrmtap.so.0.X.Y`.
A green pipeline could therefore produce a deb in which DRM capture can never start, and the
only symptom on the host is one log line before it falls back to the portal.
So parse the gate out of the Rust and apply it here, to the object being staged. This is the
same rule, not a copy of the numbers: if someone bumps the constants, this reads the new ones.
"""
m = re.search(r'libdrmtap\.so\.(\d+)\.(\d+)\.(\d+)', os.path.basename(so_path))
if not m:
# Not a versioned soname (a local dev build, say). The gate cannot be evaluated, and
# inventing a verdict would be worse than saying so.
print(f'[drm] cannot read a version out of {so_path}; skipping the ABI-gate cross-check')
return
so_ver = tuple(int(g) for g in m.groups())
# REPO_ROOT, not abspath(__file__): both callers have chdir'd into flutter/ by now.
gate_path = os.path.join(REPO_ROOT, 'libs', 'scrap', 'src', 'common', 'drmtap_dl.rs')
with open(gate_path) as f:
gate_src = f.read()
def _const(name):
mm = re.search(rf'const {name}: c_int = (\d+);', gate_src)
return int(mm.group(1)) if mm else None
major, minor = _const('DRMTAP_ABI_MAJOR'), _const('DRMTAP_ABI_MINOR')
mm = re.search(r'const DRMTAP_MIN_MINOR_PATCH: \(c_int, c_int\) = \((\d+), (\d+)\);', gate_src)
floor = (int(mm.group(1)), int(mm.group(2))) if mm else None
if major is None or minor is None or floor is None:
raise Exception(
'could not parse the libdrmtap ABI gate out of drmtap_dl.rs (DRMTAP_ABI_MAJOR / '
'DRMTAP_ABI_MINOR / DRMTAP_MIN_MINOR_PATCH). The gate moved and this check did not; '
'fix the check rather than removing it, or the pin and the gate can drift silently.')
accepted = so_ver[0] == major and so_ver[1] == minor and (so_ver[1], so_ver[2]) >= floor
if not accepted:
raise Exception(
f'the libdrmtap being packaged is {so_ver[0]}.{so_ver[1]}.{so_ver[2]}, which the '
f'runtime loader would REFUSE: drmtap_dl.rs accepts exactly major {major}, minor '
f'{minor}, patch >= {floor[1]}. Shipping it produces a deb whose DRM capture can never '
'start. Move the build pin and the gate together, or fix whichever one is wrong.')
print(f'[drm] libdrmtap {so_ver[0]}.{so_ver[1]}.{so_ver[2]} satisfies the runtime ABI gate '
f'(major {major}, minor {minor}, patch >= {floor[1]})')
def stage_libdrmtap_into_deb(so_path):
# Put the built libdrmtap object plus its soname symlink into the staged deb. Only the soname
# symlink is needed: libdrmtap is resolved by ABSOLUTE path (/usr/lib/rustdesk/libdrmtap.so.0) at
# the in-process dlopen site (drmtap_dl.rs), so the deb does NOT drop /usr/lib/rustdesk into the
# system-wide /etc/ld.so.conf.d search path, which would let this private library shadow a system
# library for every binary on the host (Debian Policy 10.2 forbids that). No ld.so.conf.d drop-in
# and no ldconfig trigger are shipped, so the stock postinst is used unchanged.
assert_so_satisfies_the_runtime_abi_gate(so_path)
so_basename = os.path.basename(so_path)
system2('mkdir -p tmpdeb/usr/lib/rustdesk')
# Quoted: so_path comes from the repo root or from DRMTAP_PREBUILT_DIR, either of which can
# contain a space, and an unquoted interpolation would split the argument and fail obscurely.
system2(f'cp "{so_path}" tmpdeb/usr/lib/rustdesk/')
system2(f'ln -sf "{so_basename}" tmpdeb/usr/lib/rustdesk/libdrmtap.so.0')
def _max_glibc_minor(path):
# Read from .dynstr rather than via objdump so packaging needs no binutils; chunked because
# librustdesk.so is ~45 MB.
best = 0
with open(path, 'rb') as f:
tail = b''
while True:
chunk = f.read(1 << 20)
if not chunk:
return best
for m in re.finditer(rb'GLIBC_2\.(\d+)', tail + chunk):
best = max(best, int(m.group(1)))
tail = chunk[-16:]
def measured_glibc_floor():
# libdrmtap is built on a newer base than the rest of the deb, so the floor is whichever staged
# object is higher -- and it moves whenever either base does.
paths = [p for p in glob.glob('tmpdeb/usr/lib/rustdesk/libdrmtap.so.0.*')
+ glob.glob('tmpdeb/usr/share/rustdesk/lib/librustdesk.so')
+ glob.glob('tmpdeb/usr/share/rustdesk/rustdesk')
if os.path.isfile(p) and not os.path.islink(p)]
minor = max((_max_glibc_minor(p) for p in paths), default=0)
if not minor:
raise Exception(
f'could not measure a GLIBC_2.x floor from any staged object ({paths or "none found"}); '
'refusing to ship the unattended-wayland variant with an undeclared libc6 floor, which '
'is what lets it install on a host where libdrmtap can never load')
return f'2.{minor}'
def retarget_control_to_drm_variant():
# Rewrite the control file that generate_control_file just produced, instead of parameterizing that
# function: the stock packaging path stays exactly as upstream wrote it, and everything specific to
# this variant lives here. The variant installs the same files as the stock package, so it must
# conflict with and replace it: you install one or the other, never both. It also needs libdrmtap's
# own runtime deps, which the stock package has no reason to carry.
path = '../res/DEBIAN/control'
floor = measured_glibc_floor()
print(f'[drm] {DRM_PACKAGE_NAME} libc6 floor measured at {floor}')
with open(path) as f:
lines = f.readlines()
out = []
for line in lines:
if line.startswith('Package: rustdesk'):
out.append(f'Package: {DRM_PACKAGE_NAME}\n')
out.append('Conflicts: rustdesk\nReplaces: rustdesk\nProvides: rustdesk\n')
elif line.startswith('Depends:'):
# 2.4.101 is where drmModeGetFB2 landed; below it libdrmtap loads and can never capture.
out.append(line.rstrip('\n') + ', libdrm2 (>= 2.4.101), libegl1, libgles2, '
f'libc6 (>= {floor})\n')
else:
out.append(line)
body = ''.join(out)
# Fail loudly rather than silently shipping a package that says `rustdesk`: a stock control file
# that stopped matching either anchor would otherwise produce a variant deb wearing the stock name.
if f'Package: {DRM_PACKAGE_NAME}\n' not in body or 'libegl1' not in body:
raise Exception(f'could not retarget {path} to the drm variant; upstream control layout changed')
with open(path, 'w') as f:
f.write(body)
def build_flutter_deb(version, features):
if not skip_cargo:
system2(f'cargo build --features {features} --lib --release')
system2(f'cargo build --locked --features {features} --lib --release')
ffi_bindgen_function_refactor()
os.chdir('flutter')
system2('flutter build linux --release')
@@ -350,20 +732,91 @@ def build_flutter_deb(version, features):
'cp ../res/pam.d/rustdesk.debian tmpdeb/etc/pam.d/rustdesk')
system2(
"echo \"#!/bin/sh\" >> tmpdeb/usr/share/rustdesk/files/polkit && chmod a+x tmpdeb/usr/share/rustdesk/files/polkit")
# Bundle libdrmtap.so only when this build actually enabled the `drm` feature, so stock packages
# stay exactly what they were. The root service dlopens it in-process by absolute path.
# `features` is the comma-joined string, so split it: a bare substring test would also match any
# future feature merely containing "drm" (drm-lease, vaapi-drm) and rename the deb to the
# consent-bypass variant without --drm ever being passed.
ships_so = 'drm' in features.split(',')
if ships_so:
# Same artifact assertion as the --package path. Under --skip-cargo nothing here rebuilt the
# binary, so `features` says what was ASKED for while the staged bundle can be anything.
assert_staged_binary_is_drm()
stage_libdrmtap_into_deb(build_libdrmtap_so())
system2('mkdir -p tmpdeb/DEBIAN')
generate_control_file(version)
if ships_so:
retarget_control_to_drm_variant()
system2('cp -a ../res/DEBIAN/* tmpdeb/DEBIAN/')
md5_file('usr/share/rustdesk/files/systemd/rustdesk.service')
md5_file_folder("tmpdeb/")
system2('dpkg-deb -b tmpdeb rustdesk.deb;')
system2('/bin/rm -rf tmpdeb/')
system2('/bin/rm -rf ../res/DEBIAN/control')
os.rename('rustdesk.deb', '../rustdesk-%s.deb' % version)
if ships_so:
# Named apart from the stock package so installing the consent-free variant is a deliberate act.
os.rename('../rustdesk-%s.deb' % version, f'../{DRM_PACKAGE_NAME}-{version}.deb')
os.chdir("..")
def build_deb_from_folder(version, binary_folder):
DRMTAP_DLOPEN_MARKER = b'/usr/lib/rustdesk/libdrmtap.so.0'
# Present only when `drm-wake` is compiled in: the runtime option constant is itself
# #[cfg(feature = "drm-wake")] (src/ipc/drm.rs). The dlopen marker above cannot stand in for it -
# `--features drm` alone produces a binary that carries the dlopen path and NO wake code, and that
# is exactly the deb this assertion is here to refuse.
DRMTAP_WAKE_MARKER = b'enable-drm-display-wake'
def _carries_drmtap_marker(path, marker=DRMTAP_DLOPEN_MARKER):
# Chunked, with an overlap of len(marker)-1 so the marker cannot be missed at a chunk boundary:
# librustdesk.so is ~45 MB and there is no reason to hold it all in memory, and the `with`
# closes deterministically instead of relying on refcounting.
with open(path, 'rb') as f:
tail = b''
while True:
chunk = f.read(1 << 20)
if not chunk:
return False
if marker in tail + chunk:
return True
tail = chunk[-(len(marker) - 1):]
def assert_staged_binary_is_drm():
"""The staged BINARY must really be a drm build before it is named the unattended-wayland
variant. That package conflicts with and replaces the stock one, so shipping a stock binary
under that name produces something that can never capture and cannot be installed alongside
what it replaced. The marker is the absolute dlopen path from drmtap_dl.rs, present only when
the feature is compiled in -- assert what was produced, not what was asked for.
Called from BOTH packaging paths. It used to guard only one of them, and `--skip-cargo` (which
is how CI packages) reaches the other, where nothing had rebuilt the binary at all.
"""
binaries = [p for p in glob.glob('tmpdeb/usr/share/rustdesk/lib/librustdesk.so')
+ glob.glob('tmpdeb/usr/share/rustdesk/rustdesk') if os.path.isfile(p)]
if not any(_carries_drmtap_marker(p) for p in binaries):
raise Exception(
f'--drm was requested but the staged bundle does not look like a drm build (no '
f'{DRMTAP_DLOPEN_MARKER.decode()} dlopen path in {binaries or "any staged binary"}); '
'refusing to package it as the unattended-wayland variant, which conflicts with and '
'replaces the stock package but could never capture')
# And the WAKE half. `--drm` enables `drm-wake` too (see get_features), and the deb is named and
# documented as the variant that can reach a machine whose screen has gone dark. The dlopen
# marker above does not distinguish them: `--features drm` alone carries it and has no wake code
# at all. Asserting only the first half is how a deb can be named for a feature it does not have.
if not any(_carries_drmtap_marker(p, DRMTAP_WAKE_MARKER) for p in binaries):
raise Exception(
f'--drm was requested but the staged binary has no {DRMTAP_WAKE_MARKER.decode()} '
f'marker in {binaries or "any staged binary"}, so it was built without `drm-wake`; '
'refusing to package it as the unattended-wayland variant, which is named and '
'documented as the build that can wake an idle-disabled display. If this fired under '
'--skip-cargo, the cargo line that produced the bundle is missing the feature: '
'--features ...,drm,drm-wake')
def build_deb_from_folder(version, binary_folder, want_drm=False):
os.chdir('flutter')
system2('mkdir -p tmpdeb/usr/bin/')
system2('mkdir -p tmpdeb/usr/share/rustdesk')
@@ -387,16 +840,62 @@ def build_deb_from_folder(version, binary_folder):
'cp ../res/rustdesk-link.desktop tmpdeb/usr/share/applications/rustdesk-link.desktop')
system2(
"echo \"#!/bin/sh\" >> tmpdeb/usr/share/rustdesk/files/polkit && chmod a+x tmpdeb/usr/share/rustdesk/files/polkit")
# Where the capture library comes from for a `--package <folder> --drm` build. Two shapes are
# supported, because two exist in practice: a bundle that already carries libdrmtap.so.0.*
# (someone staged it, e.g. a CI artifact), and a plain bundle, which is what every build path
# here actually produces -- the flutter deb builds the library straight into the staged deb, so
# nothing ever puts it inside the bundle folder. Demanding it in the bundle made this flag
# combination impossible to satisfy.
bundled_glob = glob.glob('tmpdeb/usr/share/rustdesk/libdrmtap.so.0.*')
bundle_carries_so = any(os.path.isfile(p) and not os.path.islink(p) for p in bundled_glob)
# The variant must be decided by the EXPLICIT --drm request, not merely by what happens to be
# staged: a bundle that carries the .so must NOT be shipped as the consent-bypass variant when
# --drm was never passed.
if bundle_carries_so and not want_drm:
raise Exception(
'the staged bundle carries libdrmtap.so.0.* but --drm was not passed; refusing '
'to silently ship the consent-bypass unattended-wayland variant (pass --drm to '
'build it deliberately)')
if want_drm:
# Whichever shape we are in, the staged BINARY must really be a drm build. This is the
# property the old presence-of-the-.so test stood in for, badly: a stock binary packaged as
# the unattended-wayland variant would carry the consent-bypass name, conflict with and
# replace the stock package, and never be able to capture. The marker is the absolute
# dlopen path from drmtap_dl.rs, present only when the feature is compiled in -- the same
# kind of artifact assertion as _assert_so_has_egl, and for the same reason: assert what
# was produced, not what was asked for.
assert_staged_binary_is_drm()
if bundle_carries_so:
so = _single_real_so(bundled_glob, 'the staged --drm bundle')
# The THIRD artifact source, and the last one that was missing the check: --package
# takes the .so straight out of a bundle somebody else produced, so it has the same
# exposure as DRMTAP_PREBUILT_DIR (see the comment on that branch). A CPU-only stub
# would ship, the loader would accept it, and capture would degrade to PipeWire
# without a word.
_assert_so_has_egl(so)
stage_libdrmtap_into_deb(so)
system2(f'rm -f "{so}"')
system2('rm -f tmpdeb/usr/share/rustdesk/libdrmtap.so tmpdeb/usr/share/rustdesk/libdrmtap.so.0')
else:
# Build it here, exactly as the flutter deb path does (build_libdrmtap_so asserts the
# EGL backend itself). The library is independent of the staged binary.
stage_libdrmtap_into_deb(build_libdrmtap_so())
system2('mkdir -p tmpdeb/DEBIAN')
generate_control_file(version)
# Keyed on the EXPLICIT request, not on what happened to be staged: by here a --drm build has
# its library in tmpdeb whichever of the two shapes it came from.
if want_drm:
retarget_control_to_drm_variant()
system2('cp -a ../res/DEBIAN/* tmpdeb/DEBIAN/')
md5_file('usr/share/rustdesk/files/systemd/rustdesk.service')
md5_file_folder("tmpdeb/")
system2('dpkg-deb -b tmpdeb rustdesk.deb;')
system2('/bin/rm -rf tmpdeb/')
system2('/bin/rm -rf ../res/DEBIAN/control')
os.rename('rustdesk.deb', '../rustdesk-%s.deb' % version)
if want_drm:
os.rename('../rustdesk-%s.deb' % version, f'../{DRM_PACKAGE_NAME}-{version}.deb')
os.chdir("..")
@@ -404,12 +903,18 @@ def build_flutter_dmg(version, features):
if not skip_cargo:
# set minimum osx build target, now is 10.14, which is the same as the flutter xcode project
system2(
f'MACOSX_DEPLOYMENT_TARGET=10.14 cargo build --features {features} --lib --release')
f'MACOSX_DEPLOYMENT_TARGET=10.14 cargo build --locked --features {features} --release')
# copy dylib
system2(
"cp target/release/liblibrustdesk.dylib target/release/librustdesk.dylib")
os.chdir('flutter')
system2('flutter build macos --release')
# cargo builds a single-arch dylib for the host; restrict Xcode to the same arch
# so the universal-by-default ARCHS_STANDARD doesn't try to link a missing slice.
# FLUTTER_XCODE_* env vars are forwarded to xcodebuild as build settings.
mac_arch = 'arm64' if platform.machine().lower() in ('arm64', 'aarch64') else 'x86_64'
system2(
f'FLUTTER_XCODE_ARCHS={mac_arch} FLUTTER_XCODE_ONLY_ACTIVE_ARCH=YES flutter build macos --release')
system2('cp -rf ../target/release/service ./build/macos/Build/Products/Release/RustDesk.app/Contents/MacOS/')
'''
system2(
"create-dmg --volname \"RustDesk Installer\" --window-pos 200 120 --window-size 800 400 --icon-size 100 --app-drop-link 600 185 --icon RustDesk.app 200 190 --hide-extension RustDesk.app rustdesk.dmg ./build/macos/Build/Products/Release/RustDesk.app")
@@ -420,7 +925,7 @@ def build_flutter_dmg(version, features):
def build_flutter_arch_manjaro(version, features):
if not skip_cargo:
system2(f'cargo build --features {features} --lib --release')
system2(f'cargo build --locked --features {features} --lib --release')
ffi_bindgen_function_refactor()
os.chdir('flutter')
system2('flutter build linux --release')
@@ -431,7 +936,7 @@ def build_flutter_arch_manjaro(version, features):
def build_flutter_windows(version, features, skip_portable_pack):
if not skip_cargo:
system2(f'cargo build --features {features} --lib --release')
system2(f'cargo build --locked --features {features} --lib --release')
if not os.path.exists("target/release/librustdesk.dll"):
print("cargo build failed, please check rust source code.")
exit(-1)
@@ -465,6 +970,19 @@ def main():
parser = make_parser()
args = parser.parse_args()
# Before anything with a side effect: this is a query, and a caller uses it to build the very
# binary it will then package. `get_features` stays the single definition of what a flag
# combination means; a caller that hardcodes the list instead is one edit away from compiling
# something other than what it ships.
if args.print_features:
# stdout carries the list and nothing else, so a caller can use it directly in a command
# substitution. `get_features` prints a human-readable line of its own; send that to stderr
# for this call rather than silencing it, which would change what every other path prints.
with contextlib.redirect_stdout(sys.stderr):
feats = ','.join(get_features(args))
print(feats)
return
if os.path.exists(exe_path):
os.unlink(exe_path)
if os.path.isfile('/usr/bin/pacman'):
@@ -480,20 +998,20 @@ def main():
portable = args.portable
package = args.package
if package:
build_deb_from_folder(version, package)
build_deb_from_folder(version, package, args.drm)
return
res_dir = 'resources'
external_resources(flutter, args, res_dir)
if windows:
# build virtual display dynamic library
os.chdir('libs/virtual_display/dylib')
system2('cargo build --release')
system2('cargo build --locked --release')
os.chdir('../../..')
if flutter:
build_flutter_windows(version, features, args.skip_portable_pack)
return
system2('cargo build --release --features ' + features)
system2('cargo build --locked --release --features ' + features)
# system2('upx.exe target/release/rustdesk.exe')
system2('mv target/release/rustdesk.exe target/release/RustDesk.exe')
pa = os.environ.get('P')
@@ -504,20 +1022,21 @@ def main():
'target\\release\\rustdesk.exe')
else:
print('Not signed')
os.makedirs(res_dir, exist_ok=True)
system2(
f'cp -rf target/release/RustDesk.exe {res_dir}')
os.chdir('libs/portable')
system2('pip3 install -r requirements.txt')
system2(
f'python3 ./generate.py -f ../../{res_dir} -o . -e ../../{res_dir}/rustdesk-{version}-win7-install.exe')
system2('mv ../../{res_dir}/rustdesk-{version}-win7-install.exe ../..')
system2(f'mv ../../{res_dir}/rustdesk-{version}-win7-install.exe ../..')
elif os.path.isfile('/usr/bin/pacman'):
# pacman -S -needed base-devel
system2("sed -i 's/pkgver=.*/pkgver=%s/g' res/PKGBUILD" % version)
if flutter:
build_flutter_arch_manjaro(version, features)
else:
system2('cargo build --release --features ' + features)
system2('cargo build --locked --release --features ' + features)
system2('git checkout src/ui/common.tis')
system2('strip target/release/rustdesk')
system2('ln -s res/pacman_install && ln -s res/PKGBUILD')
@@ -526,7 +1045,7 @@ def main():
version, version))
# pacman -U ./rustdesk.pkg.tar.zst
elif os.path.isfile('/usr/bin/yum'):
system2('cargo build --release --features ' + features)
system2('cargo build --locked --release --features ' + features)
system2('strip target/release/rustdesk')
system2(
"sed -i 's/Version: .*/Version: %s/g' res/rpm.spec" % version)
@@ -536,7 +1055,7 @@ def main():
version, version))
# yum localinstall rustdesk.rpm
elif os.path.isfile('/usr/bin/zypper'):
system2('cargo build --release --features ' + features)
system2('cargo build --locked --release --features ' + features)
system2('strip target/release/rustdesk')
system2(
"sed -i 's/Version: .*/Version: %s/g' res/rpm-suse.spec" % version)
@@ -555,7 +1074,7 @@ def main():
# 'mv target/release/bundle/deb/rustdesk*.deb ./flutter/rustdesk.deb')
build_flutter_deb(version, features)
else:
system2('cargo bundle --release --features ' + features)
system2('cargo --locked bundle --release --features ' + features)
if osx:
system2(
'strip target/release/bundle/osx/RustDesk.app/Contents/MacOS/rustdesk')
@@ -624,18 +1143,21 @@ def main():
system2('mkdir -p tmpdeb/usr/share/rustdesk')
system2('mv tmpdeb/usr/bin/rustdesk tmpdeb/usr/share/rustdesk/')
system2('cp libsciter-gtk.so tmpdeb/usr/share/rustdesk/')
md5_file('usr/share/rustdesk/files/systemd/rustdesk.service')
md5_file('etc/rustdesk/startwm.sh')
md5_file('etc/X11/rustdesk/xorg.conf')
md5_file('etc/pam.d/rustdesk')
md5_file('usr/share/rustdesk/libsciter-gtk.so')
md5_file_folder("tmpdeb/")
system2('dpkg-deb -b tmpdeb rustdesk.deb; /bin/rm -rf tmpdeb/')
os.rename('rustdesk.deb', 'rustdesk-%s.deb' % version)
def md5_file(fn):
md5 = hashlib.md5(open('tmpdeb/' + fn, 'rb').read()).hexdigest()
system2('echo "%s %s" >> tmpdeb/DEBIAN/md5sums' % (md5, fn))
system2('echo "%s /%s" >> tmpdeb/DEBIAN/md5sums' % (md5, fn))
def md5_file_folder(base_dir):
base_path = Path(base_dir)
for file in base_path.rglob('*'):
if file.is_file() and 'DEBIAN' not in file.parts:
relative_path = file.relative_to(base_path)
md5_file(str(relative_path))
if __name__ == "__main__":

View File

@@ -18,7 +18,7 @@ fn build_mac() {
b.flag("-DNO_InputMonitoringAuthStatus=1");
}
}
b.file(file).compile("macos");
b.flag("-std=c++17").file(file).compile("macos");
println!("cargo:rerun-if-changed={}", file);
}
@@ -68,11 +68,8 @@ fn install_android_deps() {
}
path.push(target);
println!(
"{}",
format!(
"cargo:rustc-link-search={}",
path.join("lib").to_str().unwrap()
)
"cargo:rustc-link-search={}",
path.join("lib").to_str().unwrap()
);
println!("cargo:rustc-link-lib=ndk_compat");
println!("cargo:rustc-link-lib=oboe");

137
docs/CODE_OF_CONDUCT-DE.md Normal file
View File

@@ -0,0 +1,137 @@
# Verhaltenskodex (Code of Conduct) für Mitwirkende
## Unsere Verpflichtung
Wir als Mitglieder, Mitwirkende und Führungskräfte verpflichten uns,
die Teilnahme unserer Community zu einer Erfahrung zu machen,
die für alle frei von Belästigungen ist, unabhängig von Alter, Körpergröße,
sichtbarer oder unsichtbarer Behinderung, ethnischer Zugehörigkeit,
Geschlechtsmerkmalen, Geschlechtsidentität und -ausdruck, Erfahrungsniveau,
Bildung, sozioökonomischem Status, Nationalität, persönlichem Erscheinungsbild,
Rasse, Religion oder sexueller Identität und Orientierung.
Wir verpflichten uns, so zu handeln und zu interagieren, dass wir zu einer offenen,
einladenden, vielfältigen, integrativen und lebendigen Gemeinschaft beitragen.
## Unsere Standards
Beispiele für Verhaltensweisen, die zu einem positiven Umfeld für unsere
Gemeinschaft beitragen, sind:
* Empathie und Freundlichkeit gegenüber anderen Menschen zu zeigen
* Respektvoll gegenüber anderen Meinungen, Sichtweisen und Erfahrungen zu sein
* Das Vergeben von sowie das großzügige Empfangen von konstruktivem Feedback
* Verantwortung übernehmen, sich bei den Betroffenen entschuldigen
und aus den Erfahrungen lernen
* Nicht darauf zu achten, was das Beste für sich selbst,
sondern zu Achten, was das Beste für die gesamte Community ist
Beispiele für nicht akzeptables Verhalten sind:
* Die Verwendung sexualisierter bzw. anstößiger Sprache oder Bilder
sowie sexuelle Aufmerksamkeit oder Annäherungsversuche jeglicher Art
* Trolling, beleidigende oder herabwürdigende Kommentare
sowie persönliche oder politische Angriffe
* Öffentliche sowie private Belästigung
* Das Teilen privater Informationen anderer Leute ohne deren explizite Zustimmung,
wie bspw. die physische oder die E-Mail-Adresse
* Anderes Verhalten, das in einem professionellen Umfeld begründeter Weise als
unangemessen angesehen werden könnte
## Durchsetzungsbefugnisse
Die Leiter der Community sind dafür verantwortlich, unsere Standards für
akzeptables Verhalten zu klären und durchzusetzen und werden angemessene
und faire Korrekturmaßnahmen ergreifen, wenn sie ein Verhalten als unangemessen,
bedrohlich, beleidigend oder schädlich erachten.
Die Leiter der Community haben das Recht und die Pflicht, Kommentare, Commits,
Code, Wiki-Bearbeitungen, Issues und andere Beiträge, die nicht mit dem
Verhaltenskodex vereinbar sind, zu entfernen, zu bearbeiten oder abzulehnen.
Sie werden, falls angebracht, die Gründe für Moderationsentscheidungen mitteilen.
## Geltungsbereich
Dieser Verhaltenskodex gilt in allen Community-Bereichen und auch dann, wenn
eine Person die Community offiziell in öffentlichen Bereichen vertritt.
Beispiele für die Vertretung unserer Community sind die Verwendung einer
offiziellen E-Mail-Adresse, das Posten über einen offiziellen
Social-Media-Account oder die Tätigkeit als ernannter
Vertreter bei einer Online- oder Präsenzveranstaltung.
## Geltendmachung
Fälle von missbräuchlichem, belästigendem oder anderweitig inakzeptablem Verhalten können
den für die Durchsetzung zuständigen Community-Leitern
unter [info@rustdesk.com](mailto:info@rustdesk.com) gemeldet werden.
Jeder Fall wird umgehend und fair geprüft und untersucht.
## Richtlinien zur Geltendmachung
Die Community-Leiter werden die folgenden Community-Auswirkungsrichtlinien befolgen,
um die Konsequenzen für jede Handlung zu bestimmen, die sie als Verstoß gegen diesen
Verhaltenskodex ansehen:
### 1. Korrektur
**Auswirkungen auf die Community**: Verwendung unangemessener Sprache oder anderes
Verhalten, welches als unprofessionell oder in der Community unerwünscht angesehen wird.
**Konsequenz**: Eine private, schriftliche Verwarnung durch die Leiter der Community,
in der die Art des Verstoßes klar dargelegt und erklärt wird, warum das
Verhalten unangemessen war. Eine öffentliche Entschuldigung kann verlangt werden.
### 2. Warnung
**Auswirkungen auf die Community**: Ein Verstoß durch einen einzelnen Vorfall
oder eine Reihe von Handlungen.
**Konsequenz**: Eine Verwarnung mit Konsequenzen für das weitere Verhalten. Keine
Interaktion mit den beteiligten Personen, einschließlich unaufgeforderter Interaktion mit
denjenigen, die den Verhaltenskodex durchsetzen, für einen bestimmten Zeitraum. Dies
schließt die Vermeidung von Interaktionen in Gemeinschaftsräumen sowie externen Kanälen
wie sozialen Medien ein. Ein Verstoß gegen diese Bedingungen kann zu einer vorübergehenden oder
dauerhaften Sperrung führen.
### 3. Temporärer Sperrung
**Auswirkungen auf die Community**: Ein schwerwiegender Verstoß gegen die Community-Standards,
einschließlich anhaltend unangemessenem Verhalten.
**Konsequenz**: Eine vorübergehende Sperrung jeglicher Art von Interaktion oder öffentlicher
Kommunikation mit der Community für einen bestimmten Zeitraum. Während dieses Zeitraums sind
keine öffentlichen oder privaten Interaktionen mit den betroffenen Personen,
einschließlich unaufgeforderter Interaktionen mit denjenigen,
die den Verhaltenskodex durchsetzen, erlaubt.
Ein Verstoß gegen diese Bedingungen kann zu einer dauerhaften Sperrung führen.
### 4. Dauerhafte Sperrung
**Auswirkungen auf die Community**: Wiederholte Verstöße gegen die Community-Standards,
einschließlich anhaltend unangemessenem Verhalten, Belästigung einer
Person oder Aggression gegenüber oder Herabwürdigung von Personengruppen.
**Konsequenz**: Ein dauerhafter Ausschluss von jeglicher öffentlicher
Interaktion innerhalb der Community.
## Quellenangabe
Dieser Verhaltenskodex ist eine Adaption des [Contributor Covenant][homepage],
Version 2.0, verfügbar unter
[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
Die Richtlinien zu den Auswirkungen auf die Gemeinschaft wurden inspiriert von
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
Für Antworten auf häufig gestellte Fragen zu diesem Verhaltenskodex siehe die
häufig gestellten Fragen (FAQ) unter
[https://www.contributor-covenant.org/faq][FAQ]. Übersetzungen sind verfügbar
unter [https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

143
docs/CODE_OF_CONDUCT-FR.md Normal file
View File

@@ -0,0 +1,143 @@
# Code de conduite des contributeurs
## Notre engagement
En tant que membres, contributeurs et responsables, nous nous engageons à faire
de la participation à notre communauté une expérience exempte de harcèlement pour
tous, indépendamment de l'âge, de la taille corporelle, du handicap visible ou
invisible, de l'origine ethnique, des caractéristiques sexuelles, de l'identité
et de l'expression de genre, du niveau d'expérience, de l'éducation, du statut
socio-économique, de la nationalité, de l'apparence personnelle, de la race, de
la religion ou de l'identité et de l'orientation sexuelle.
Nous nous engageons à agir et à interagir de manière à contribuer à une
communauté ouverte, accueillante, diversifiée, inclusive et saine.
## Nos standards
Exemples de comportements qui contribuent à un environnement positif pour notre
communauté :
* Faire preuve d'empathie et de bienveillance envers les autres
* Respecter les opinions, les points de vue et les expériences différents
* Donner et accepter gracieusement les retours constructifs
* Assumer ses responsabilités, s'excuser auprès des personnes affectées par nos
erreurs et apprendre de l'expérience
* Se concentrer sur ce qui est le mieux non seulement pour nous en tant
qu'individus, mais pour l'ensemble de la communauté
Exemples de comportements inacceptables :
* L'utilisation de langage ou d'images à caractère sexuel, et les attentions ou
avances sexuelles de quelque nature que ce soit
* Le trolling, les commentaires insultants ou désobligeants, et les attaques
personnelles ou politiques
* Le harcèlement public ou privé
* La publication d'informations privées d'autrui, telles qu'une adresse physique
ou électronique, sans autorisation explicite
* Tout autre comportement qui pourrait raisonnablement être considéré comme
inapproprié dans un cadre professionnel
## Responsabilités en matière d'application
Les responsables de la communauté sont chargés de clarifier et d'appliquer nos
standards de comportement acceptable et prendront des mesures correctives
appropriées et équitables en réponse à tout comportement qu'ils jugent
inapproprié, menaçant, offensant ou nuisible.
Les responsables de la communauté ont le droit et la responsabilité de
supprimer, modifier ou rejeter les commentaires, commits, code, modifications
du wiki, issues et autres contributions qui ne sont pas conformes à ce Code de
conduite, et communiqueront les raisons de leurs décisions de modération le cas
échéant.
## Portée
Ce Code de conduite s'applique dans tous les espaces communautaires, et
s'applique également lorsqu'une personne représente officiellement la communauté
dans les espaces publics. Les exemples de représentation de notre communauté
incluent l'utilisation d'une adresse e-mail officielle, la publication via un
compte de réseau social officiel, ou le fait d'agir en tant que représentant
désigné lors d'un événement en ligne ou hors ligne.
## Application
Les cas de comportements abusifs, harcelants ou autrement inacceptables peuvent
être signalés aux responsables de la communauté chargés de l'application à
[info@rustdesk.com](mailto:info@rustdesk.com).
Toutes les plaintes seront examinées et feront l'objet d'une enquête rapide et
équitable.
Tous les responsables de la communauté sont tenus de respecter la vie privée et
la sécurité de la personne ayant signalé un incident.
## Directives d'application
Les responsables de la communauté suivront ces Directives d'impact communautaire
pour déterminer les conséquences de toute action qu'ils jugent en violation de ce
Code de conduite :
### 1. Correction
**Impact communautaire** : Utilisation d'un langage inapproprié ou autre
comportement jugé non professionnel ou indésirable dans la communauté.
**Conséquence** : Un avertissement écrit et privé de la part des responsables de
la communauté, expliquant la nature de la violation et pourquoi le comportement
était inapproprié. Des excuses publiques peuvent être demandées.
### 2. Avertissement
**Impact communautaire** : Une violation par un incident isolé ou une série
d'actions.
**Conséquence** : Un avertissement avec des conséquences en cas de comportement
répété. Aucune interaction avec les personnes impliquées, y compris les
interactions non sollicitées avec les personnes chargées d'appliquer le Code de
conduite, pendant une période déterminée. Cela inclut d'éviter les interactions
dans les espaces communautaires ainsi que dans les canaux externes comme les
réseaux sociaux. Le non-respect de ces conditions peut entraîner une exclusion
temporaire ou permanente.
### 3. Exclusion temporaire
**Impact communautaire** : Une violation grave des standards communautaires, y
compris un comportement inapproprié persistant.
**Conséquence** : Une exclusion temporaire de toute interaction ou communication
publique avec la communauté pendant une période déterminée. Aucune interaction
publique ou privée avec les personnes impliquées, y compris les interactions non
sollicitées avec les personnes chargées d'appliquer le Code de conduite, n'est
autorisée pendant cette période. Le non-respect de ces conditions peut entraîner
une exclusion permanente.
### 4. Exclusion permanente
**Impact communautaire** : Démontrer un schéma de violation des standards
communautaires, y compris un comportement inapproprié persistant, le harcèlement
d'une personne, ou une agression envers des catégories de personnes ou leur
dénigrement.
**Conséquence** : Une exclusion permanente de toute interaction publique au sein
de la communauté.
## Attribution
Ce Code de conduite est adapté du [Contributor Covenant][homepage], version 2.0,
disponible à l'adresse
[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
Les Directives d'impact communautaire ont été inspirées par
[l'échelle d'application du code de conduite de Mozilla][Mozilla CoC].
Pour des réponses aux questions fréquentes sur ce code de conduite, consultez la
FAQ à l'adresse [https://www.contributor-covenant.org/faq][FAQ]. Des traductions
sont disponibles à l'adresse
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

133
docs/CODE_OF_CONDUCT-KR.md Normal file
View File

@@ -0,0 +1,133 @@
# 기여자 계약 행동 강령
## 우리의 서약
회원, 기여자, 리더로서 우리는 나이, 신체 크기, 눈에
보이거나 보이지 않는 장애, 민족, 성 특성, 성 정체성 및
표현, 경험 수준, 교육, 사회 경제적 지위, 국적, 외모,
인종, 종교, 성적 정체성 및 지향에 관계없이 모든 사람이
괴롭힘 없이 커뮤니티에 참여할 수 있도록 할 것을
서약합니다.
우리는 개방적이고 환영하며 다양하고 포용적이며 건강한 커뮤니티에
기여하는 방식으로 행동하고 교류할 것을 약속합니다.
## 우리의 표준
커뮤니티의 긍정적인 환경에 기여하는 행동의 예는
다음과 같습니다:
* 다른 사람들에게 공감과 친절을 보여주기
* 다양한 의견, 관점, 경험을 존중하기
* 건설적인 피드백을 제공하고 우아하게 받아들이기
* 우리의 실수로 인해 영향을 받은 사람들에게 책임을 받아들이고 사과하며
그 경험을 통해 배우기
* 우리 개인뿐만 아니라 전체 커뮤니티에 가장 좋은 것이 무엇인지
집중하기
용납할 수 없는 행동의 예는 다음과 같습니다:
* 성적인 언어 또는 이미지의 사용, 모든 종류의 성적 관심 또는
접근 행위
* 트롤링, 모욕적이거나 경멸적인 댓글, 개인적 또는 정치적 공격
* 공개적 또는 사적인 괴롭힘
* 명시적인 허가 없이 타인의 실제 주소 또는 이메일 주소와 같은
개인정보를 게시하는 행위
* 직업적 환경에서 합리적으로 부적절하다고 간주될 수 있는
기타 행위
## 시행 책임
커뮤니티 리더는 허용되는 행동의 기준을 명확히 하고 시행할
책임이 있으며 부적절하거나 위협적이거나 모욕적이거나
유해하다고 판단되는 행동에 대해 적절하고 공정한 시정 조치를
취합니다.
커뮤니티 리더는 본 행동 강령에 부합하지 않는 댓글, 커밋,
코드, 위키 편집, 이슈 및 기타 기여를 삭제, 편집 또는 거부할
권한과 책임이 있으며, 적절한 경우 중재 결정의 이유를
전달합니다.
## 범위
본 행동 강령은 모든 커뮤니티 공간에서 적용되며, 개인이 공개
공간에서 커뮤니티를 공식적으로 대표하는 경우에도 적용됩니다.
커뮤니티를 대표하는 예로는 공식 이메일 주소 사용, 공식 소셜 미디어
계정을 통한 게시, 온라인 또는 오프라인 이벤트에서 지정된 대표자로
활동하는 것 등이 있습니다.
## 시행
모욕적, 괴롭힘 또는 기타 용납할 수 없는 행동은
[info@rustdesk.com](mailto:info@rustdesk.com)으로 법 집행을 담당하는 커뮤니티 리더에게
신고하실 수 있습니다.
모든 불만 사항은 신속하고 공정하게 검토 및 조사됩니다.
모든 커뮤니티 리더는 모든 사건 신고자의 사생활과 보안을 존중할 의무가
있습니다.
## 시행 지침
커뮤니티 리더는 이 행동 강령을 위반한 것으로 간주되는 모든 행동에 대한
결과를 결정할 때 다음 커뮤니티 영향 지침을 따릅니다:
### 1. 수정
**커뮤니티 영향**: 커뮤니티에서 비전문적이거나 환영받지 못하는
것으로 간주되는 부적절한 언어 사용이나 기타 행위입니다.
**결과**: 커뮤니티 리더의 비공개 서면 경고. 위반 사항의 성격과
해당 행동이 부적절했던 이유를 명확히 설명해야 합니다.
공개 사과를 요청할 수도 있습니다.
### 2. 경고
**커뮤니티 영향**: 단일 사건 또는 일련의 행위를 통한
위반입니다.
**결과**: 지속적인 행동에 대한 경고 및 결과. 행동 강령 시행 담당자와의
원치 않는 상호작용을 포함하여 관련자와의 상호작용은 일정
기간 동안 금지됩니다. 여기에는 공동 공간 및 소셜 미디어와
같은 외부 채널에서의 상호작용 금지가 포함됩니다. 이러한
조건을 위반할 경우 일시적 또는 영구적으로 이용이 금지될 수
있습니다.
### 3. 일시 금지
**커뮤니티 영향**: 지속적인 부적절한 행동을 포함하여
커뮤니티 기준을 심각하게 위반한 경우입니다.
**결과**: 일정 기간 동안 커뮤니티와의 모든 상호작용이나 공개적인 소통이
일시적으로 금지됩니다. 이 기간 동안에는 행동 강령을 시행하는
사람들과의 원치 않는 상호작용을 포함하여 관련자들과의 공개적 또는
사적인 상호작용이 허용되지 않습니다.
이러한 조건을 위반할 경우 영구적으로 이용이 금지될 수 있습니다.
### 4. 영구 금지
**커뮤니티 영향**: 지속적인 부적절한 행동, 특정 개인에 대한 괴롭힘,
특정 계층에 대한 공격성 또는 비하 등 공동체 기준을 위반하는
행동을 보이는 경우입니다.
**결과**: 공동체 내 모든 종류의 공개적인 상호작용이 영구적으로
금지됩니다.
## 귀속
본 행동 강령은 [Contributor Covenant][homepage] 버전 2.0을 바탕으로 작성되었으며
[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0]에서
확인하실 수 있습니다.
커뮤니티 영향 지침은
[Mozilla's code of conduct enforcement ladder][Mozilla CoC]에서 영감을 받았습니다.
본 행동 강령에 대한 일반적인 질문은 [https://www.contributor-covenant.org/faq][FAQ]에서 FAQ를
참조하세요. 번역은 [https://www.contributor-covenant.org/translations][translations]에서
확인하실 수 있습니다.
[homepage]: https://www.contributor-covenant.org
[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

125
docs/CODE_OF_CONDUCT-NO.md Normal file
View File

@@ -0,0 +1,125 @@
# Atferdskodeks for bidragsyterpaktern
## Hva Vi Står For
Vi som medlemer, bidragere, og ledere står for å skape ett hat-fritt felleskap,
uansett alder, kroppstørrelse, synlig eller usynlige funksjonsnedsettninger,
etnesitet, kjønns karaktertrekk, kjønnsidentitet, kunnskapsnivå, utdanning,
sosial-økonomisk status, nasjonalitet, utsende, rase, religion, eller seksual
identitet og orientasjon.
Vi står for åpen, velkommende, mangfold, inklusiv og sunn oppførsel i vårt felleskap.
## Våre Standarer
Eksempler på oppførsel som hjelper ett positivt felleskap inkluderer:
* Vise empati og vennlighet mot andre mennesker
* Være respektfull ovenfor ulike meninger, synspunkter og erfaringer
* Gi og ta konstruktiv kritikk i beste mening
* Akseptere ansvar og unskylde seg for de som er utsatt av våre feil,
og lære av disse
* Fokusere på det som er best ikke bare for individer, men for felleskapet
Eksempler på uakseptabel oppførsel inkluderer:
* Bruk av seksualisert språk eller bilder, og seksual oppmerksomhet.
* Troll-ene, fornermende og nedsettende kommentarer, og personlig eller politiske angrep
* Offentlig eller privat trakassering
* Publisering av andres private informasjon, sånn som bosteds- og epost-addresser,
uten deres godskjenning.
* Andre rettningslinjer som kan bli sett på som upassende i en profesjonell setting.
## Håndhevingsansvar
Felleskapets ledere har ansvar for å klarifisere og håndheve våre standarer av
akseptert oppførsel og vill ta rimelige og rettferdige handliger som respons på
oppførsel de anser som upassende, truende, fornermende eller skadelig.
Felleskapets ledere har retten og ansvaret til å fjerne, redigere, eller avslå
kommentarer, commits, kode, wiki endringer, issues, og andre birag som ikke
samsvarer med disse etiske rettningslinjene, og vill kommunisere grunner for
moderatorenes valg når passende.
## Omfang
Disse etiske rettningslinjene gjelder innenfor alle platformene til felleskapet, og
de gjelder også når ett individ representerer felleskapet på offentlige medier.
Eksempler på representasjon av vårt felleskap inkluderer bruke av offisielle e-mail
addresser, publisering gjennom en offisiell sosial media bruker, eller oppførsel som en
utpekt representant på digitale og fysiske arrangsjemanger.
## Håndheving
Hendelser av misbruk, trakasserende eller på noen måte uakseptert oppførsel kann
bli raportert til felleskapets ledere med ansvar for håndheving på
[info@rustdesk.com](mailto:info@rustdesk.com).
All tilbakemelding vill bli sett gjennom og investigert rettferdig så fort som mulig.
Alle felleskapets ledere er obligert til å respektere privatlivet og sikkerhetet ovenfor
den som raporterer en hendelse.
## Håndhevings Guide
Felleskapets ledere vill følge disse Rettningslinjene for sammfunspåvirkning med
tanke på konsekvenser for en handling de anser i brudd med disse etiske rettningslinjene:
### 1. Korreksjon
**Sammfunspåvirkning**: Bruk av upassende språk eller annen oppførsel ansett som
uprofesjonelt eller uvelkommen i dette felleskapet.
**Konsekvens**: En privat, skrevet advarsel fra en leder av felleskapet, som
klarifiserer grunnlaget til hvorfor denne oppførselen var upassende. En offentlig
unskyldning kan bli forespurt.
### 2. Advarsel
**Sammfunspåvirkning**: Ett brudd på en singulær hendelse eller en serie handlinger.
**Konsekvens**: En advarsel med konsekvenser for kontinuerende oppførsel. Ingen
interaksjon med individene involvert, inkluderer uoppfordret interaksjoner med
de som håndhever disse etiske rettningslinjene, er tillat for en spesifisert tidsperiode.
Dette inkluderer å unngå interaksjoner i felleskapets platformer, samt eksterne
kanaler, som f.eks sosial media. Brudd av disse vilkårene kan føre til midlertidig
eller permanent bannlysning.
### 3. Midlertidig Bannlysning
**Sammfunspåvirkning**: Ett særiøst brudd på felleskapets standarer, inkludert
vedvarende upassende oppførsel.
**Konsekvens**: En midlertidig bannlysning fra noen som helst interaksjon eller
offentlig kommunikasjon med felleskapet for en spesifisert tidsperiode. Ingen
interaksjon med individene involvert, inkluderer uoppfordret interaksjoner med
de som håndhever disse etiske rettningslinjene, er tillat for denne perioden.
Brudd på disse vilkårene kan føre til permanent bannlysning.
### 4. Permanent Bannlysning
**Sammfunspåvirkning**: Demonstasjon av mønster i brudd på felleskapets standarer,
inklusivt vedvarende upassende oppførsel, trakassering av ett individ, eller
aggresjon mot eller nedsettelse av grupper individer.
**Konsekvens**: En permanent bannlysning fra alle offentlige interaksjoner i
felleskapet
## Attribusjon
Disse etiske rettningslinjene er adaptert fra [Contributor Covenant][homepage],
versjon 2.0, tilgjengelig ved
[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
Sammfunspåvirknings guid inspirert av
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For svar til vanlige spørsmål angående disse etiske rettningslinjene, se FAQ på
[https://www.contributor-covenant.org/faq][FAQ]. Oversettelse tilgjengelig
ved [https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

View File

@@ -0,0 +1,85 @@
# Codul de Conduită al Contributorilor
## Angajamentul Nostru
Noi, ca membri, contribuitori și lideri, ne angajăm să facem ca participarea în comunitatea noastră să fie o experiență fără hărțuire pentru toată lumea, indiferent de vârstă, dimensiunea corpului, dizabilități vizibile sau invizibile, etnie, caracteristici sexuale, identitate și exprimare de gen, nivel de experiență, educație, statut socio-economic, naționalitate, aspect personal, rasă, religie sau identitate și orientare sexuală.
Ne angajăm să acționăm și să interacționăm în moduri care contribuie la o comunitate deschisă, primitoare, diversă, incluzivă și sănătoasă.
## Standardele Noastre
Exemple de comportamente care contribuie la un mediu pozitiv pentru comunitatea noastră includ:
* Demonstrarea empatiei și a bunătății față de ceilalți
* Respectarea opiniilor, punctelor de vedere și experiențelor diferite
* Oferirea și acceptarea cu grație a feedback-ului constructiv
* Asumarea responsabilității și cererea de scuze celor afectați de greșelile noastre și învățarea din experiență
* Concentrarea pe ceea ce este cel mai bun nu doar pentru noi ca indivizi, ci pentru întreaga comunitate
Exemple de comportamente inacceptabile includ:
* Utilizarea limbajului sau imaginilor sexualizate, precum și atenția sau avansurile sexuale de orice fel
* Trollare, insulte sau comentarii denigratoare și atacuri personale sau politice
* Hărțuire publică sau privată
* Publicarea informațiilor private ale altora, cum ar fi adresa fizică sau de e-mail, fără permisiunea explicită
* Alte comportamente care ar putea fi considerate inadecvate într-un cadru profesional
## Responsabilități de Aplicare
Liderii comunității sunt responsabili pentru clarificarea și aplicarea standardelor noastre de comportament acceptabil și vor lua măsuri corective adecvate și echitabile ca răspuns la orice comportament pe care îl consideră inadecvat, amenințător, ofensator sau dăunător.
Liderii comunității au dreptul și responsabilitatea de a elimina, edita sau respinge comentarii, commit-uri, cod, editări wiki, probleme și alte contribuții care nu se aliniază acestui Cod de Conduită și vor comunica motivele pentru deciziile de moderare atunci când este cazul.
## Domeniu de Aplicare
Acest Cod de Conduită se aplică în toate spațiile comunității și se aplică și atunci când un individ reprezintă oficial comunitatea în spații publice.
Exemple de reprezentare a comunității includ utilizarea unei adrese de e-mail oficiale, postarea printr-un cont oficial de social media sau acționarea ca reprezentant desemnat la un eveniment online sau offline.
## Aplicare
Cazurile de comportament abuziv, hărțuitor sau altfel inacceptabil pot fi raportate liderilor comunității responsabili pentru aplicare la [info@rustdesk.com](mailto:info@rustdesk.com).
Toate plângerile vor fi revizuite și investigate prompt și corect.
Toți liderii comunității sunt obligați să respecte confidențialitatea și securitatea persoanei care raportează orice incident.
## Ghiduri de Aplicare
Liderii comunității vor urma aceste Ghiduri privind Impactul Comunității pentru a stabili consecințele pentru orice acțiune pe care o consideră o încălcare a acestui Cod de Conduită:
### 1. Corectare
**Impact asupra comunității**: Utilizarea limbajului neadecvat sau alte comportamente considerate neprofesionale sau nedorite în comunitate.
**Consecință**: O avertizare scrisă și privată din partea liderilor comunității, oferind claritate asupra naturii încălcării și o explicație despre motivul pentru care comportamentul a fost inadecvat. Poate fi cerută o scuză publică.
### 2. Avertisment
**Impact asupra comunității**: Încălcare printr-un incident singular sau o serie de acțiuni.
**Consecință**: Un avertisment cu consecințe pentru continuarea comportamentului. Nicio interacțiune cu persoanele implicate, inclusiv interacțiuni nesolicitate cu cei care aplică Codul de Conduită, pentru o perioadă specificată. Aceasta include evitarea interacțiunilor în spațiile comunității, precum și pe canale externe, cum ar fi rețelele sociale. Încălcarea acestor termeni poate duce la o suspendare temporară sau permanentă.
### 3. Suspendare Temporară
**Impact asupra comunității**: O încălcare serioasă a standardelor comunității, inclusiv comportament neadecvat susținut.
**Consecință**: Suspendare temporară de la orice tip de interacțiune sau comunicare publică cu comunitatea pentru o perioadă specificată. Nicio interacțiune publică sau privată cu persoanele implicate, inclusiv interacțiuni nesolicitate cu cei care aplică Codul de Conduită, nu este permisă în această perioadă. Încălcarea acestor termeni poate duce la o interdicție permanentă.
### 4. Interdicție Permanentă
**Impact asupra comunității**: Demonstrând un tipar de încălcare a standardelor comunității, inclusiv comportament neadecvat susținut, hărțuire a unei persoane sau agresiune față de sau denigrare a unor grupuri de persoane.
**Consecință**: Interdicție permanentă de la orice tip de interacțiune publică în cadrul comunității.
## Atribuire
Acest Cod de Conduită este adaptat din [Contributor Covenant][homepage], versiunea 2.0, disponibil la [https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
Ghidurile privind Impactul Comunității au fost inspirate de [scara de aplicare a codului de conduită Mozilla][Mozilla CoC].
Pentru răspunsuri la întrebări frecvente despre acest cod de conduită, vezi FAQ la [https://www.contributor-covenant.org/faq][FAQ]. Traduceri sunt disponibile la [https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

View File

@@ -107,7 +107,7 @@ Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within

View File

@@ -1,42 +1,42 @@
# Beitr<EFBFBD>ge zu RustDesk
# Beiträge zu RustDesk
RustDesk begr<EFBFBD><EFBFBD>t Beitr<EFBFBD>ge von jedem. Hier sind die Richtlinien, wenn Sie uns
helfen m<EFBFBD>chten:
RustDesk begrüßt Beiträge von jedem. Hier sind die Richtlinien, wenn Sie uns
helfen möchten:
## Beitr<EFBFBD>ge
## Beiträge
Beitr<EFBFBD>ge zu RustDesk oder seinen Abh<EFBFBD>ngigkeiten sollten in Form von Pull
Beiträge zu RustDesk oder seinen Abhängigkeiten sollten in Form von Pull
Requests auf GitHub erfolgen. Jeder Pull Request wird von einem Hauptakteur
(jemand mit der Erlaubnis, Korrekturen einzubringen) gepr<EFBFBD>ft und entweder in den
Hauptbaum eingef<EFBFBD>gt oder Feedback f<EFBFBD>r notwendige <EFBFBD>nderungen gegeben. Alle
Beitr<EFBFBD>ge sollten diesem Format folgen, auch die von Hauptakteuren.
(jemand mit der Erlaubnis, Korrekturen einzubringen) geprüft und entweder in den
Hauptbaum eingefügt oder Feedback für notwendige Änderungen gegeben. Alle
Beiträge sollten diesem Format folgen, auch die von Hauptakteuren.
Wenn Sie an einem Problem arbeiten m<EFBFBD>chten, melden Sie es bitte zuerst an, indem
Sie auf GitHub erkl<EFBFBD>ren, dass Sie daran arbeiten m<EFBFBD>chten. Damit soll verhindert
werden, dass Beitr<EFBFBD>ge zum gleichen Thema doppelt bearbeitet werden.
Wenn Sie an einem Problem arbeiten möchten, melden Sie es bitte zuerst an, indem
Sie auf GitHub erklären, dass Sie daran arbeiten möchten. Damit soll verhindert
werden, dass Beiträge zum gleichen Thema doppelt bearbeitet werden.
## Checkliste f<EFBFBD>r Pull Requests
## Checkliste für Pull Requests
- Verzweigen Sie sich vom Master-Branch und, falls n<EFBFBD>tig, wechseln Sie zum
- Verzweigen Sie sich vom Master-Branch und, falls nötig, wechseln Sie zum
aktuellen Master-Branch, bevor Sie Ihren Pull Request einreichen. Wenn das
Zusammenf<EFBFBD>hren mit dem Master nicht reibungslos funktioniert, werden Sie
m<EFBFBD>glicherweise aufgefordert, Ihre <EFBFBD>nderungen zu <EFBFBD>berarbeiten.
Zusammenführen mit dem Master nicht reibungslos funktioniert, werden Sie
möglicherweise aufgefordert, Ihre Änderungen zu überarbeiten.
- Commits sollten so klein wie m<EFBFBD>glich sein und gleichzeitig sicherstellen, dass
jeder Commit unabh<EFBFBD>ngig voneinander korrekt ist (d. h., jeder Commit sollte
sich <EFBFBD>bersetzen lassen und Tests bestehen).
- Commits sollten so klein wie möglich sein und gleichzeitig sicherstellen, dass
jeder Commit unabhängig voneinander korrekt ist (d. h., jeder Commit sollte
sich übersetzen lassen und Tests bestehen).
- Commits sollten von einem "Herkunftszertifikat f<EFBFBD>r Entwickler"
- Commits sollten von einem "Herkunftszertifikat für Entwickler"
(https://developercertificate.org) begleitet werden, das besagt, dass Sie (und
ggf. Ihr Arbeitgeber) mit den Bedingungen der [Projektlizenz](../LICENCE)
einverstanden sind. In Git ist dies die Option `-s` f<EFBFBD>r `git commit`.
einverstanden sind. In Git ist dies die Option `-s` für `git commit`.
- Wenn Ihr Patch nicht begutachtet wird oder Sie eine bestimmte Person zur
Begutachtung ben<EFBFBD>tigen, k<EFBFBD>nnen Sie einem Gutachter mit @ antworten und um eine
Begutachtung des Pull Requests oder einen Kommentar bitten. Sie k<EFBFBD>nnen auch
Begutachtung benötigen, können Sie einem Gutachter mit @ antworten und um eine
Begutachtung des Pull Requests oder einen Kommentar bitten. Sie können auch
per [E-Mail](mailto:info@rustdesk.com) um eine Begutachtung bitten.
- F<EFBFBD>gen Sie Tests hinzu, die sich auf den behobenen Fehler oder die neue
- Fügen Sie Tests hinzu, die sich auf den behobenen Fehler oder die neue
Funktion beziehen.
Spezifische Git-Anweisungen finden Sie im [GitHub-Workflow](https://github.com/servo/servo/wiki/GitHub-workflow).
@@ -47,4 +47,4 @@ https://github.com/rustdesk/rustdesk/blob/master/docs/CODE_OF_CONDUCT.md
## Kommunikation
RustDesk-Mitarbeiter arbeiten h<EFBFBD>ufig im [Discord](https://discord.gg/nDceKgxnkV).
RustDesk-Mitarbeiter arbeiten häufig im [Discord](https://discord.gg/nDceKgxnkV).

55
docs/CONTRIBUTING-FR.md Normal file
View File

@@ -0,0 +1,55 @@
# Contribuer à RustDesk
RustDesk accueille les contributions de tous. Voici les directives si vous
envisagez de nous aider :
## Contributions
Les contributions à RustDesk ou à ses dépendances doivent être soumises sous
forme de pull requests GitHub. Chaque pull request sera examinée par un
contributeur principal (une personne ayant la permission d'intégrer des
correctifs) et sera soit intégrée dans la branche principale, soit accompagnée
de retours sur les modifications requises. Toutes les contributions doivent
suivre ce format, même celles des contributeurs principaux.
Si vous souhaitez travailler sur une issue, veuillez d'abord la revendiquer en
commentant sur l'issue GitHub indiquant que vous souhaitez la traiter. Cela
permet d'éviter les efforts en double de la part des contributeurs sur la même
issue.
## Liste de vérification pour les pull requests
- Partez de la branche master et, si nécessaire, effectuez un rebase sur la
branche master actuelle avant de soumettre votre pull request. Si elle ne
fusionne pas proprement avec master, il vous sera peut-être demandé de
rebaser vos modifications.
- Les commits doivent être aussi petits que possible, tout en s'assurant que
chaque commit est correct de manière indépendante (c.-à-d. que chaque commit
doit compiler et passer les tests).
- Les commits doivent être accompagnés d'une signature Developer Certificate of
Origin (http://developercertificate.org), indiquant que vous (et votre
employeur le cas échéant) acceptez d'être liés par les termes de la
[licence du projet](../LICENCE). Dans git, il s'agit de l'option `-s` de
`git commit`.
- Si votre correctif n'est pas examiné ou si vous avez besoin qu'une personne
spécifique l'examine, vous pouvez @-mentionner un relecteur pour demander une
revue dans la pull request ou un commentaire, ou vous pouvez demander une
revue par [e-mail](mailto:info@rustdesk.com).
- Ajoutez des tests relatifs au bug corrigé ou à la nouvelle fonctionnalité.
Pour des instructions git spécifiques, consultez le
[GitHub workflow 101](https://github.com/servo/servo/wiki/GitHub-workflow).
## Conduite
https://github.com/rustdesk/rustdesk/blob/master/docs/CODE_OF_CONDUCT.md
## Communication
Les contributeurs de RustDesk se retrouvent fréquemment sur
[Discord](https://discord.gg/nDceKgxnkV).

46
docs/CONTRIBUTING-KR.md Normal file
View File

@@ -0,0 +1,46 @@
# RustDesk 기여하기
RustDesk는 모든 분들의 참여를 환영합니다. 저희를 도와주실 생각이 있으시다면
다음 지침을 따르세요:
## 기여
RustDesk 또는 그 종속성에 대한 기여는 GitHub 풀 리퀘스트 형태로
이루어져야 합니다. 각 풀 리퀘스트는 핵심 기여자 (패치 적용 권한이
있는 사람)가 검토하여 메인 트리에 추가하거나 필요한 변경 사항에
대한 피드백을 제공합니다. 핵심 기여자의 기여를 포함하여 모든 기여는
이 형식을 따라야 합니다.
이슈에 대해 작업하고 싶으시면 먼저 해당 이슈에 대해 작업하고 싶다는
댓글을 달아 해당 이슈를 요청하세요. 이는 동일한 이슈에 대한 기여자의
중복된 노력을 방지하기 위한 것입니다.
## 풀 리퀘스트 체크리스트
- Master 브랜치에서 브랜치를 만들고, 필요한 경우 풀 리퀘스트를 제출하기
전에 현재 마스터 브랜치로 리베이스하세요. 마스터 브랜치와 깔끔하게
병합되지 않으면 변경 사항을 리베이스하라는 요청을 받을 수 있습니다.
- 커밋은 가능한 한 작아야 하지만, 각 커밋이 독립적으로 올바른지 확인
해야 합니다 (즉, 각 커밋은 컴파일되어 테스트를 통과해야 함).
- 커밋에는 개발자 출처 증명서 (http://developercertificate.org)
서명이 첨부되어야 하며, 이는 귀하 (및 해당되는 경우 고용주)가
[프로젝트 라이선스](../LICENCE). 조건에 구속되는 데 동의한다는 것을 나타냅니다.
git에서는 `git commit``-s` 옵션입니다
- 패치가 검토되지 않거나 특정인이 검토해야 하는 경우, 풀 리퀘스트나
댓글에서 검토자에게 @-답글을 보내 검토를 요청하거나
[이메일](mailto:info@rustdesk.com)을 통해 검토를 요청할 수 있습니다.
- 수정된 버그 또는 새 기능과 관련된 테스트를 추가합니다.
구체적인 git 지침은, [GitHub workflow 101](https://github.com/servo/servo/wiki/GitHub-workflow)을 참조하세요.
## 행동 강령
https://github.com/rustdesk/rustdesk/blob/master/docs/CODE_OF_CONDUCT.md
## 커뮤니케이션
RustDesk 기여자들은 [Discord](https://discord.gg/nDceKgxnkV)에서 활동하고 있습니다.

46
docs/CONTRIBUTING-NO.md Normal file
View File

@@ -0,0 +1,46 @@
# Bidrag til RustDesk
RustDesk er åpene for bidrag fra alle. Her er reglene for de som har lyst til å
hjelpe oss:
## Bidrag
Bidrag til RustDesk eller deres avhengigheter burde være i form av GitHub pull requests.
Hver pull request vill bli sett igjennom av en kjerne bidrager (noen med autoritet til
å godkjenne endringene) og enten bli sendt til main treet eller respondert med
tilbakemelding på endringer som er nødvendig. Alle bidrag burde følge dette formate
også de fra kjerne bidragere.
Om du ønsker å jobbe på en issue må du huske å gjøre krav på den først. Dette
kann gjøres ved å kommentere på den GitHub issue-en du ønsker å jobbe på.
Dette er for å hindre duplikat innsats på samme problem.
## Pull Request Sjekkliste
- Lag en gren fra master grenen og, hvis det er nødvendig, rebase den til den nåværende
master grenen før du sender inn din pull request. Hvis ikke dette gjøres på rent
vis vill du bli spurt om å rebase dine endringer.
- Commits burde være så små som mulig, samtidig som de må være korrekt uavhenging av hverandre
(hver commit burde kompilere og bestå tester).
- Commits burde være akkopaniert med en Developer Certificate of Origin
(http://developercertificate.org), som indikerer att du (og din arbeidsgiver
i det tilfellet) godkjenner å bli knyttet til vilkårene av [prosjekt lisensen](../LICENCE).
Ved bruk av git er dette `-s` opsjonen til `git commit`.
- Hvis dine endringer ikke blir sett eller hvis du trenger en spesefik person til
å se på dem kan du @-svare en med autoritet til å godkjenne dine endringer.
Dette kann gjøres i en pull request, en kommentar eller via epost på [email](mailto:info@rustdesk.com).
- Legg til tester relevant til en fikset bug eller en ny tilgjengelighet.
For spesefike git instruksjoner, se [GitHub workflow 101](https://github.com/servo/servo/wiki/GitHub-workflow).
## Oppførsel
https://github.com/rustdesk/rustdesk/blob/master/docs/CODE_OF_CONDUCT.md
## Kommunikasjon
RustDesk bidragere burker [Discord](https://discord.gg/nDceKgxnkV).

31
docs/CONTRIBUTING-RO.md Normal file
View File

@@ -0,0 +1,31 @@
# Contribuții la RustDesk
RustDesk primește cu plăcere contribuții din partea tuturor. Iată ghidurile dacă te gândești să ne ajuți:
## Contribuții
Contribuțiile la RustDesk sau la dependențele sale ar trebui făcute sub forma de pull request-uri pe GitHub. Fiecare pull request va fi revizuit de un contributor principal (cineva cu permisiunea de a aplica patch-uri) și fie va fi integrat în arborele principal, fie vor fi oferite sugestii pentru modificările necesare. Toate contribuțiile trebuie să urmeze acest format, chiar și cele ale contributorilor principali.
Dacă dorești să lucrezi la o problemă, te rugăm să o revendici mai întâi comentând pe GitHub issue-ul pe care vrei să lucrezi. Aceasta previne eforturi duplicate din partea contributorilor asupra aceleiași probleme.
## Lista de verificare pentru Pull Request
- Creează un branch din branch-ul `master` și, dacă este necesar, fă rebase la branch-ul `master` curent înainte de a trimite pull request-ul. Dacă nu se poate integra curat cu `master`, ți se poate cere să faci rebase la modificările tale.
- Commit-urile ar trebui să fie cât mai mici posibil, asigurând totodată că fiecare commit este corect independent (adică fiecare commit ar trebui să compileze și să treacă testele).
- Commit-urile trebuie să fie însoțite de un semnătura Developer Certificate of Origin (http://developercertificate.org), care indică faptul că tu (și angajatorul tău, dacă este cazul) ești de acord să respecți termenii [licenței proiectului](../LICENCE). În git, aceasta este opțiunea `-s` la `git commit`.
- Dacă patch-ul tău nu este revizuit sau ai nevoie ca o anumită persoană să-l revizuiască, poți @-reply unui reviewer cerând o revizuire în pull request sau într-un comentariu, sau poți solicita o revizuire prin [email](mailto:info@rustdesk.com).
- Adaugă teste relevante pentru bug-ul corectat sau pentru funcționalitatea nouă.
Pentru instrucțiuni specifice git, vezi [GitHub workflow 101](https://github.com/servo/servo/wiki/GitHub-workflow).
## Conduită
[Codul de Conduită RustDesk](https://github.com/rustdesk/rustdesk/blob/master/docs/CODE_OF_CONDUCT.md)
## Comunicare
Contributorii RustDesk frecventează [Discord](https://discord.gg/nDceKgxnkV).

View File

@@ -5,18 +5,14 @@ RustDesk приветствует вклад каждого.
## Вклад в развитие
Вклады в развитие RustDesk или его зависимости должны быть
сделаны в виде `pull request` на GitHub. Каждый такой
`pull request` будет рассмотрен основным участником
(кем-то, у кого есть разрешение на влив исправлений)
и либо помещен в основное дерево, либо Вам будет дан отзыв
о необходимых правках. Все материалы должны соответствовать
этому формату, даже те, которые поступают от основных авторов.
Вклады в развитие RustDesk или его зависимости должны быть сделаны в виде `pull request` на GitHub.
Каждый такой `pull request` будет рассмотрен основным участником (кем-то, у кого есть разрешение
на влив исправлений) и либо помещен в основное дерево, либо Вам будет дан отзыв о необходимых правках.
Все материалы должны соответствовать этому формату, даже те, которые поступают от основных авторов.
Если вы хотите поработать над какой-либо проблемой, то пожалуйста,
сначала напишите об этом, создав тикет на GitHub, и описав,
над чем вы хотите поработать. Это делается для того, чтобы
предотвратить дублирование усилий участников по одному и тому же вопросу.
Если вы хотите поработать над какой-либо проблемой, то пожалуйста, сначала напишите об этом,
создав `issue` на GitHub, и описав, над чем вы хотите поработать. Это делается для того,
чтобы предотвратить дублирование усилий участников по одному и тому же вопросу.
## Контрольный список для Ваших `pull request`
@@ -24,13 +20,13 @@ RustDesk приветствует вклад каждого.
ветку перед отправкой `pull request`. При наличии конфликтов слияния вам будет
предложено их устранить, возможно при помощи того же `rebase`.
- Коммиты должны быть, по возможности, небольшим, при этом гарантируя, что каждаый
- Коммиты должны быть, по возможности, небольшими, при этом гарантируя, что каждый
коммит является независимо правильным (т.е., каждый коммит должен компилироваться и проходить тесты).
- Коммиты должны сопровождаться `Developer Certificate of Origin`
(http://developercertificate.org) подписью, которая укажет на то, что вы (и
ваш работодатель, если это применимо) согласны соблюдать условия
[лицензии проекта](../LICENCE). В `git` это флаг `-s` при использовании `git commit`
- Коммиты должны сопровождаться подписью `Developer Certificate of Origin`
(http://developercertificate.org), которая укажет на то, что вы (и ваш работодатель,
если это применимо) согласны соблюдать условия [лицензии проекта](../LICENCE).
В `git` это флаг `-s` при использовании `git commit`
- Если ваш патч не проходит рецензирование или вам нужно,
чтобы его проверил конкретный человек, Вы можете ответить рецензенту через `@`,
@@ -40,7 +36,7 @@ RustDesk приветствует вклад каждого.
Для получения конкретных инструкций `git` см. [GitHub workflow 101](https://github.com/servo/servo/wiki/Github-workflow).
## Кодекс поведения участников и вкладчиков
## Правила поведения участников и вкладчиков
Нормы поведения внутри сообщества подробно описаны [здесь](CODE_OF_CONDUCT-RU.md).

View File

@@ -1,6 +1,6 @@
# Contributing to RustDesk
RustDesk welcomes contribution from everyone. Here are the guidelines if you are
RustDesk welcomes contributions from everyone. Here are the guidelines if you are
thinking of helping us:
## Contributions

View File

@@ -1,14 +0,0 @@
Nach dem Start von Dev-Container im Docker-Container wird ein Linux-Bin<69>rprogramm im Debug-Modus erstellt.
Derzeit bietet Dev-Container Linux- und Android-Builds sowohl im Debug- als auch im Release-Modus an.
Nachfolgend finden Sie eine Tabelle mit Befehlen, die im Stammverzeichnis des Projekts ausgef<65>hrt werden m<>ssen, um bestimmte Builds zu erstellen.
Kommando|Build-Typ|Modus
-|-|-|
`.devcontainer/build.sh --debug linux`|Linux|debug
`.devcontainer/build.sh --release linux`|Linux|release
`.devcontainer/build.sh --debug android`|android-arm64|debug
`.devcontainer/build.sh --release android`|android-arm64|release

View File

@@ -1,14 +0,0 @@
Dopo l'avvio di devcontainer nel contenitore docker, viene creato un binario linux in modalità debug.
Attualmente devcontainer consente creazione build Linux e Android sia in modalità debug che in modalità rilascio.
Di seguito è riportata la tabella dei comandi da eseguire dalla root del progetto per la creazione di build specifiche.
Comando|Tipo build|Modo
-|-|-|
`.devcontainer/build.sh --debug linux`|Linux|debug
`.devcontainer/build.sh --release linux`|Linux|release
`.devcontainer/build.sh --debug android`|android-arm64|debug
`.devcontainer/build.sh --release android`|android-arm64|release

View File

@@ -1,14 +0,0 @@
docker コンテナで devcontainer を起動すると、デバッグモードの linux バイナリが作成されます。
現在 devcontainer では、Linux と android のビルドをデバッグモードとリリースモードの両方で提供しています。
以下は、特定のビルドを作成するためにプロジェクトのルートから実行するコマンドの表になります。
コマンド|ビルド タイプ|モード
-|-|-|
`.devcontainer/build.sh --debug linux`|Linux|debug
`.devcontainer/build.sh --release linux`|Linux|release
`.devcontainer/build.sh --debug android`|android-arm64|debug
`.devcontainer/build.sh --release android`|android-arm64|release

View File

@@ -1,15 +0,0 @@
Na de start van devcontainer in docker container wordt een linux binaire in foutmodus aangemaakt.
Momenteel biedt devcontainer linux en android builds in zowel foutopsporing- als uitgave modus.
Hieronder staat de tabel met commando's die vanuit de root van het project moeten worden
uitgevoerd om specifieke builds te maken.
Commando|Build Type|Modus
-|-|-|
`.devcontainer/build.sh --debug linux`|Linux|debug
`.devcontainer/build.sh --release linux`|Linux|release
`.devcontainer/build.sh --debug android`|android-arm64|debug
`.devcontainer/build.sh --release android`|android-arm64|debug

View File

@@ -1,14 +0,0 @@
Po uruchomieniu devcontainer w kontenerze docker, tworzony jest plik binarny linux w trybue debugowania.
Obecnie devcontainer oferuje kompilowanie wersji dla linux i android w obu trybach - debugowania i wersji finalnej.
Poniżej tabela poleceń do uruchomienia z głównego folderu do tworzenia wybranych kompilacji.
Polecenie|Typ kompilacji|Tryb
-|-|-|
`.devcontainer/build.sh --debug linux`|Linux|debug
`.devcontainer/build.sh --release linux`|Linux|release
`.devcontainer/build.sh --debug android`|android-arm64|debug
`.devcontainer/build.sh --release android`|android-arm64|debug

View File

@@ -1,12 +0,0 @@
Docker konteynerinde devcontainer'ın başlatılmasından sonra, hata ayıklama modunda bir Linux ikili dosyası oluşturulur.
Şu anda devcontainer, hata ayıklama ve sürüm modunda hem Linux hem de Android derlemeleri sunmaktadır.
Aşağıda, belirli derlemeler oluşturmak için projenin kökünden çalıştırılması gereken komutlar yer almaktadır.
Komut | Derleme Türü | Mod
-|-|-
`.devcontainer/build.sh --debug linux` | Linux | hata ayıklama
`.devcontainer/build.sh --release linux` | Linux | sürüm
`.devcontainer/build.sh --debug android` | Android-arm64 | hata ayıklama
`.devcontainer/build.sh --release android` | Android-arm64 | sürüm

View File

@@ -1,14 +0,0 @@
After the start of devcontainer in docker container, a linux binary in debug mode is created.
Currently devcontainer offers linux and android builds in both debug and release mode.
Below is the table on commands to run from root of the project for creating specific builds.
Command|Build Type|Mode
-|-|-|
`.devcontainer/build.sh --debug linux`|Linux|debug
`.devcontainer/build.sh --release linux`|Linux|release
`.devcontainer/build.sh --debug android`|android-arm64|debug
`.devcontainer/build.sh --release android`|android-arm64|release

View File

@@ -9,9 +9,9 @@
<b> لغتك الأم, <a href="https://github.com/rustdesk/doc.rustdesk.com">Doc</a> و <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a>, README نحن بحاجة إلى مساعدتك لترجمة هذا </b>
</p>
[Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) :تواصل معنا عبر
[Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk) :تواصل معنا عبر
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-%D8%A7%D9%84%D9%85%D9%8A%D8%B2%D8%A7%D8%AA%20%D8%A7%D9%84%D9%85%D8%AA%D9%82%D8%AF%D9%85%D8%A9-blue)](https://rustdesk.com/pricing.html)
.Rustبرنامج آخر لسطح المكتب عن بعد، مكتوب بـ
يعمل خارج الصندوق، لا حاجة إلى إعدادات. لديك سيطرة كاملة على بياناتك، دون مخاوف بشأن الأمن. يمكنك استخدام خادم
@@ -27,6 +27,7 @@
[**BINARY تنزيل**](https://github.com/rustdesk/rustdesk/releases)
## التبعيات
لواجهة المستخدم الرسومية [sciter](https://sciter.com/) نسخة سطح المكتب تستخدم

View File

@@ -9,10 +9,10 @@
<b>Potřebujeme Vaši pomoc s překladem tohoto README, <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">uživatelského rozhraní aplikace RustDesk</a> a <a href="https://github.com/rustdesk/doc.rustdesk.com">dokumentace k ní</a> do vašeho jazyka</b>
</p>
Popovídejte si s námi: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
Popovídejte si s námi: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-Pokro%C4%8Dil%C3%A9%20Funkce-blue)](https://rustdesk.com/pricing.html)
Zase další software pro přístup k ploše na dálku, naprogramovaný v jazyce Rust. Funguje hned tak, jak je není třeba žádného nastavování. Svá data máte ve svých rukách, bez obav o zabezpečení. Je možné používat námi poskytovaný propojovací/předávací (relay) server, [vytvořit si svůj vlastní](https://rustdesk.com/server), nebo [si dokonce svůj vlastní naprogramovat](https://github.com/rustdesk/rustdesk-server-demo), budete-li chtít.

View File

@@ -9,13 +9,13 @@
<b>Vi har brug for din hjælp til at oversætte denne README, <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> og <a href=" https://github.com/rustdesk/doc.rustdesk.com">Dokument</a> til dit modersmål</b>
</p>
Chat med os: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
Chat med os: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-Avancerede%20Funktioner-blue)](https://rustdesk.com/pricing.html)
Endnu en fjernskrivebordssoftware, skrevet i Rust. Fungerer ud af æsken, ingen konfiguration påkrævet. Du har fuld kontrol over dine data uden bekymringer om sikkerhed. Du kan bruge vores rendezvous/relay-server, [opsætte din egen](https://rustdesk.com/server), eller [skrive din egen rendezvous/relay-server](https://github.com/rustdesk/rustdesk- server-demo).
RustDesk hilser bidrag fra alle velkommen. Se [`docs/CONTRIBUTING.md`](docs/CONTRIBUTING.md) for at få hjælp til at komme i gang.
RustDesk hilser bidrag fra alle velkommen. Se [`docs/CONTRIBUTING.md`](CONTRIBUTING.md) for at få hjælp til at komme i gang.
[**PROGRAM DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)

View File

@@ -1,17 +1,21 @@
<p align="center">
<img src="../res/logo-header.svg" alt="RustDesk - Your remote desktop"><br>
<a href="#freie-öffentliche-server">Server</a> •
<img src="../res/logo-header.svg" alt="RustDesk - Dein Remote-Desktop"><br>
<a href="#grobe-schritte-zum-kompilieren">Kompilieren</a> •
<a href="#auf-docker-kompilieren">Docker</a> •
<a href="#dateistruktur">Dateistruktur</a> •
<a href="#screenshots">Screenshots</a><br>
[<a href="../README.md">English</a>] | [<a href="README-UA.md">Українська</a>] | [<a href="README-CS.md">česky</a>] | [<a href="README-ZH.md">中文</a>] | [<a href="README-HU.md">Magyar</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FA.md">فارسی</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-ID.md">Indonesian</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>] | [<a href="README-KR.md">한국어</a>] | [<a href="README-AR.md">العربي</a>] | [<a href="README-VN.md">Tiếng Việt</a>] | [<a href="README-DA.md">Dansk</a>] | [<a href="README-GR.md">Ελληνικά</a>]<br>
[<a href="docs/README-UA.md">Українська</a>] | [<a href="docs/README-CS.md">česky</a>] | [<a href="docs/README-ZH.md">中文</a>] | [<a href="docs/README-HU.md">Magyar</a>] | [<a href="docs/README-ES.md">Español</a>] | [<a href="docs/README-FA.md">فارسی</a>] | [<a href="docs/README-FR.md">Français</a>] | [<a href="docs/README-DE.md">Deutsch</a>] | [<a href="docs/README-PL.md">Polski</a>] | [<a href="docs/README-ID.md">Indonesian</a>] | [<a href="docs/README-FI.md">Suomi</a>] | [<a href="docs/README-ML.md">മലയാളം</a>] | [<a href="docs/README-JP.md">日本語</a>] | [<a href="docs/README-NL.md">Nederlands</a>] | [<a href="docs/README-IT.md">Italiano</a>] | [<a href="docs/README-RU.md">Русский</a>] | [<a href="docs/README-PTBR.md">Português (Brasil)</a>] | [<a href="docs/README-EO.md">Esperanto</a>] | [<a href="docs/README-KR.md">한국어</a>] | [<a href="docs/README-AR.md">العربي</a>] | [<a href="docs/README-VN.md">Tiếng Việt</a>] | [<a href="docs/README-DA.md">Dansk</a>] | [<a href="docs/README-GR.md">Ελληνικά</a>] | [<a href="docs/README-TR.md">Türkçe</a>] | [<a href="docs/README-NO.md">Norsk</a>] | [<a href="docs/README-RO.md">Română</a>]<br>
<b>Wir brauchen Ihre Hilfe, um dieses README, die <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk-Benutzeroberfläche</a> und die <a href="https://github.com/rustdesk/doc.rustdesk.com">Dokumentation</a> in Ihre Muttersprache zu übersetzen.</b>
</p>
Reden Sie mit uns auf: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
> [!Caution]
> **Haftungsausschluss bei Missbrauch::** <br>
> Die Entwickler von RustDesk billigen oder unterstützen keine unethische oder illegale Nutzung dieser Software. Missbrauch, wie unbefugter Zugriff, unbefugte Kontrolle oder Verletzung der Privatsphäre, verstößt strikt gegen unsere Richtlinien. Die Autoren sind nicht verantwortlich für jeglichen Missbrauch der Anwendung.
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
Reden Sie mit uns auf: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-Erweiterte%20Funktionen-blue)](https://rustdesk.com/pricing.html)
RustDesk ist eine in Rust geschriebene Remote-Desktop-Software, die out of the box ohne besondere Konfiguration funktioniert. Sie haben die volle Kontrolle über Ihre Daten und müssen sich keine Sorgen um die Sicherheit machen. Sie können unseren Rendezvous/Relay-Server nutzen, [einen eigenen Server aufsetzen](https://rustdesk.com/server) oder [einen eigenen Server programmieren](https://github.com/rustdesk/rustdesk-server-demo).
@@ -23,11 +27,14 @@ RustDesk heißt jegliche Mitarbeit willkommen. Schauen Sie sich [CONTRIBUTING-DE
[**Programm herunterladen**](https://github.com/rustdesk/rustdesk/releases)
[**Nächtliche Erstellung**](https://github.com/rustdesk/rustdesk/releases/tag/nightly)
[**Nightly Builds**](https://github.com/rustdesk/rustdesk/releases/tag/nightly)
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
[<img src="https://f-droid.org/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
[<img src="https://flathub.org/api/badge?svg&locale=en"
alt="Get it on Flathub"
height="80">](https://flathub.org/apps/com.rustdesk.RustDesk)
## Abhängigkeiten
@@ -59,18 +66,19 @@ Bitte laden Sie die dynamische Bibliothek Sciter selbst herunter.
```sh
sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev \
libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake make \
libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libpam0g-dev
```
### openSUSE Tumbleweed
```sh
sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel
sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel pam-devel
```
### Fedora 28 (CentOS 8)
```sh
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel pam-devel
```
### Arch (Manjaro)
@@ -109,7 +117,7 @@ cd
```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
git clone https://github.com/rustdesk/rustdesk
git clone --recurse-submodules https://github.com/rustdesk/rustdesk
cd rustdesk
mkdir -p target/debug
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
@@ -124,6 +132,7 @@ Beginnen Sie damit, das Repository zu klonen und den Docker-Container zu bauen:
```sh
git clone https://github.com/rustdesk/rustdesk
cd rustdesk
git submodule update --init --recursive
docker build -t "rustdesk-builder" .
```
@@ -152,6 +161,7 @@ Bitte stellen Sie sicher, dass Sie diese Befehle im Stammverzeichnis des RustDes
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: Video-Codec, Konfiguration, TCP/UDP-Wrapper, Protokoll-Puffer, fs-Funktionen für Dateitransfer und ein paar andere nützliche Funktionen
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: Bildschirmaufnahme
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: Plattformspezifische Maus- und Tastatursteuerung
- **[libs/clipboard](https://github.com/rustdesk/rustdesk/tree/master/libs/clipboard)**: Datei kopieren und einfügen Implementierung für Windows, Linux, macOS.
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: GUI
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: Audio/Zwischenablage/Eingabe/Videodienste und Netzwerkverbindungen
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: Starten einer Peer-Verbindung
@@ -162,10 +172,11 @@ Bitte stellen Sie sicher, dass Sie diese Befehle im Stammverzeichnis des RustDes
## Screenshots
![image](https://user-images.githubusercontent.com/71636191/113112362-ae4deb80-923b-11eb-957d-ff88daad4f06.png)
![Verbindungsmanager](https://github.com/rustdesk/rustdesk/assets/28412477/db82d4e7-c4bc-4823-8e6f-6af7eadf7651)
![image](https://user-images.githubusercontent.com/71636191/113112619-f705a480-923b-11eb-911d-97e984ef52b6.png)
![Verbunden zu einem Windows PC](https://github.com/rustdesk/rustdesk/assets/28412477/9baa91e9-3362-4d06-aa1a-7518edcbd7ea)
![image](https://user-images.githubusercontent.com/71636191/113112857-3fbd5d80-923c-11eb-9836-768325faf906.png)
![Dateiübertragung](https://github.com/rustdesk/rustdesk/assets/28412477/39511ad3-aa9a-4f8c-8947-1cce286a46ad)
![TCP-Tunneling](https://github.com/rustdesk/rustdesk/assets/28412477/78e8708f-e87e-4570-8373-1360033ea6c5)
![image](https://user-images.githubusercontent.com/71636191/135385039-38fdbd72-379a-422d-b97f-33df71fb1cec.png)

View File

@@ -9,9 +9,9 @@
<b>Ni bezonas helpon traduki tiun README kaj <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">la interfacon</a> al via denaska lingvo</b>
</p>
Babili kun ni: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
Babili kun ni: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-Altnivela%20Funkcioj-blue)](https://rustdesk.com/pricing.html)
Denove alia fora labortabla programo, skribita en Rust. Ĝi funkcias elskatole, ne bezonas konfiguraĵon. Vi havas la tutan kontrolon sur viaj datumoj, sen zorgo pri sekureco. Vi povas uzi nian servilon rendezvous/relajsan, [agordi vian propran](https://rustdesk.com/server), aŭ [skribi vian propran servilon rendezvous/relajsan](https://github.com/rustdesk/rustdesk-server-demo).

View File

@@ -9,12 +9,18 @@
<b>Necesitamos tu ayuda para traducir este README a tu idioma</b>
</p>
Chatea con nosotros: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
> [!Caution]
> **Descargo de responsabilidad por mal uso:** <br>
> Los desarrolladores de RustDesk no aprueban ni apoyan ningún uso no ético o ilegal de este software. El mal uso, como el acceso no autorizado, el control o la invasión de la privacidad, va estrictamente en contra de nuestras directrices. Los autores no se hacen responsables de ningún uso indebido de la aplicación.
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
Chatea con nosotros: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-Caracter%C3%ADsticas%20Avanzadas-blue)](https://rustdesk.com/pricing.html)
Otro software de escritorio remoto, escrito en Rust. Funciona de forma inmediata, sin necesidad de configuración. Tienes el control total de tus datos, sin preocupaciones sobre la seguridad. Puedes utilizar nuestro servidor de rendezvous/relay, [instalar el tuyo](https://rustdesk.com/server), o [escribir tu propio servidor rendezvous/relay](https://github.com/rustdesk/rustdesk-server-demo).
![image](https://user-images.githubusercontent.com/71636191/171661982-430285f0-2e12-4b1d-9957-4a58e375304d.png)
RustDesk agradece la contribución de todo el mundo. Lee [`docs/CONTRIBUTING.md`](CONTRIBUTING.md) para ayuda para empezar.
[**¿Cómo funciona rustdesk?**](https://github.com/rustdesk/rustdesk/wiki/How-does-RustDesk-work%3F)
@@ -24,12 +30,15 @@ RustDesk agradece la contribución de todo el mundo. Lee [`docs/CONTRIBUTING.md`
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
[<img src="https://flathub.org/api/badge?svg&locale=en"
alt="Get it on Flathub"
height="80">](https://flathub.org/apps/com.rustdesk.RustDesk)
## Dependencias
La versión Desktop usa [Sciter](https://sciter.com/) o Flutter para el GUI, este tutorial es solo para Sciter.
Las versiones de escritorio utilizan Flutter o Sciter (obsoleto) para GUI, este tutorial es sólo para Sciter, ya que es más fácil y más amigable para empezar. Echa un vistazo a nuestro [CI](https://github.com/rustdesk/rustdesk/blob/master/.github/workflows/flutter-build.yml) para la construcción de la versión Flutter.
Por favor descarga la librería dinámica de Sciter tu mismo.
Por favor descarga la librería dinámica de Sciter tú mismo.
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
@@ -51,13 +60,21 @@ Por favor descarga la librería dinámica de Sciter tu mismo.
### Ubuntu 18 (Debian 10)
```sh
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev \
libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake make \
libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libpam0g-dev
```
### openSUSE Tumbleweed
```sh
sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel pam-devel
```
### Fedora 28 (CentOS 8)
```sh
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel pam-devel
```
### Arch (Manjaro)
@@ -96,12 +113,12 @@ cd
```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
git clone https://github.com/rustdesk/rustdesk
git clone --recurse-submodules https://github.com/rustdesk/rustdesk
cd rustdesk
mkdir -p target/debug
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
mv libsciter-gtk.so target/debug
cargo run
VCPKG_ROOT=$HOME/vcpkg cargo run
```
## Como compilar con Docker
@@ -111,10 +128,11 @@ Empieza clonando el repositorio y compilando el contenedor de docker:
```sh
git clone https://github.com/rustdesk/rustdesk
cd rustdesk
git submodule update --init --recursive
docker build -t "rustdesk-builder" .
```
Entonces, cada vez que necesites compilar una modificación, ejecuta el siguiente comando:
Entonces, cada vez que necesites compilar la aplicación, ejecuta el siguiente comando:
```sh
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
@@ -147,12 +165,16 @@ Por favor, asegurate de que estás ejecutando estos comandos desde la raíz del
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: Flutter, código para moviles
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: Javascript para el cliente web Flutter
> [!Precaución]
> **Descargo de responsabilidad por uso indebido:** <br>
> Los desarrolladores de RustDesk no aprueban ni apoyan ningún uso no ético o ilegal de este software. El uso indebido, como el acceso no autorizado, el control o la invasión de la privacidad, está estrictamente en contra de nuestras directrices. Los autores no son responsables de ningún uso indebido de la aplicación.
## Capturas de pantalla
![image](https://user-images.githubusercontent.com/71636191/113112362-ae4deb80-923b-11eb-957d-ff88daad4f06.png)
![Connection Manager](https://github.com/rustdesk/rustdesk/assets/28412477/db82d4e7-c4bc-4823-8e6f-6af7eadf7651)
![image](https://user-images.githubusercontent.com/71636191/113112619-f705a480-923b-11eb-911d-97e984ef52b6.png)
![Connected to a Windows PC](https://github.com/rustdesk/rustdesk/assets/28412477/9baa91e9-3362-4d06-aa1a-7518edcbd7ea)
![image](https://user-images.githubusercontent.com/71636191/113112857-3fbd5d80-923c-11eb-9836-768325faf906.png)
![File Transfer](https://github.com/rustdesk/rustdesk/assets/28412477/39511ad3-aa9a-4f8c-8947-1cce286a46ad)
![image](https://user-images.githubusercontent.com/71636191/135385039-38fdbd72-379a-422d-b97f-33df71fb1cec.png)
![TCP Tunneling](https://github.com/rustdesk/rustdesk/assets/28412477/78e8708f-e87e-4570-8373-1360033ea6c5)

View File

@@ -9,10 +9,10 @@
<p align="center" dir="auto">[<a href="../README.md">English</a>] | [<a href="README-UA.md">Українська</a>] | [<a href="README-CS.md">česky</a>] | [<a href="README-ZH.md">中文</a>] | [<a href="README-HU.md">Magyar</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-ID.md">Indonesian</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>] | [<a href="README-KR.md">한국어</a>] | [<a href="README-AR.md">العربي</a>] | [<a href="README-VN.md">Tiếng Việt</a>] | [<a href="README-GR.md">Ελληνικά</a>]</p>
<p dir="rtl" align="center"><b>برای ترجمه این سند (README)، <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang" dir="rtl">رابط کاربری RustDesk</a>، <a href="https://github.com/rustdesk/doc.rustdesk.com" dir="rtl">و مستندات آن</a> به زبان مادری شما به کمکتان نیازمندیم. </b></p>
با ما گفتگو کنید: [Reddit](https://www.reddit.com/r/rustdesk) | [Twitter](https://twitter.com/rustdesk) | [Discord](https://discord.gg/nDceKgxnkV)
با ما گفتگو کنید: [Reddit](https://www.reddit.com/r/rustdesk) | [Twitter](https://twitter.com/rustdesk) | [Discord](https://discord.gg/nDceKgxnkV) | [YouTube](https://www.youtube.com/@rustdesk)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-%D9%88%DB%8C%DA%98%DA%AF%DB%8C%E2%80%8C%D9%87%D8%A7%DB%8C%20%D9%BE%DB%8C%D8%B4%D8%B1%D9%81%D8%AA%D9%87-blue)](https://rustdesk.com/pricing.html)
راست‌دسک (RustDesk) نرم‌افزاری برای کارکردن با رایانه‌ی رومیزی از راه دور است و با زبان برنامه‌نویسی Rust نوشته شده است. نیاز به تنظیمات چندانی ندارد و شما را قادر می سازد تا بدون نگرانی از امنیت اطلاعات خود بر آن‌ها کنترل کامل داشته باشید.

View File

@@ -9,9 +9,9 @@
<b>Tarvitsemme apua tämän README-tiedoston kääntämiseksi äidinkielellesi</b>
</p>
Juttele meidän kanssa: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
Juttele meidän kanssa: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-Edistyneet%20Ominaisuudet-blue)](https://rustdesk.com/pricing.html)
Vielä yksi etätyöpöytäohjelmisto, ohjelmoitu Rust-kielellä. Toimii suoraan pakkauksesta, ei tarvitse asetusta. Hallitset täysin tietojasi, ei tarvitse murehtia turvallisuutta. Voit käyttää meidän rendezvous/relay-palvelinta, [aseta omasi](https://rustdesk.com/server), tai [kirjoittaa oma rendezvous/relay-palvelin](https://github.com/rustdesk/rustdesk-server-demo).

View File

@@ -9,9 +9,9 @@
<b>Nous avons besoin de votre aide pour traduire ce README dans votre langue maternelle</b>.
</p>
Chattez avec nous : [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
Chattez avec nous : [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-Fonctionnalit%C3%A9s%20Avanc%C3%A9es-blue)](https://rustdesk.com/pricing.html)
Encore un autre logiciel de bureau à distance, écrit en Rust. Fonctionne directement, aucune configuration n'est nécessaire. Vous avez le contrôle total de vos données, sans aucun souci de sécurité. Vous pouvez utiliser notre serveur de rendez-vous/relais, [configurer le vôtre](https://rustdesk.com/server), ou [écrire votre propre serveur de rendez-vous/relais](https://github.com/rustdesk/rustdesk-server-demo).
@@ -34,9 +34,9 @@ Les versions de bureau utilisent [sciter](https://sciter.com/) pour l'interface
- Installez [vcpkg](https://github.com/microsoft/vcpkg), et définissez correctement la variable d'environnement `VCPKG_ROOT`.
- Windows : vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static aom:x64-windows-static
- Linux/Osx : vcpkg install libvpx libyuv opus aom
- Linux/macOS : vcpkg install libvpx libyuv opus aom
- Exécuter `cargo run`
- Exécutez `cargo run`
## Comment compiler/build sous Linux
@@ -93,7 +93,7 @@ cd rustdesk
mkdir -p target/debug
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
mv libsciter-gtk.so target/debug
Exécution du cargo
cargo run
```
## Comment construire avec Docker
@@ -137,6 +137,10 @@ Veuillez vous assurer que vous exécutez ces commandes à partir de la racine du
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)** : Communiquer avec [rustdesk-server](https://github.com/rustdesk/rustdesk-server), attendre une connexion distante directe (TCP hole punching) ou relayée.
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)** : code spécifique à la plateforme
> [!Attention]
> **Avertissement contre l'utilisation abusive:** <br>
> Les développeurs de RustDesk ne cautionnent ni ne soutiennent aucune utilisation non éthique ou illégale de ce logiciel. Toute utilisation abusive, telle que l'accès non autorisé, le contrôle ou l'invasion de la vie privée, est strictement contraire à nos directives. Les auteurs ne sont pas responsables de toute utilisation abusive de l'application.
## Images
![image](https://user-images.githubusercontent.com/71636191/113112362-ae4deb80-923b-11eb-957d-ff88daad4f06.png)

View File

@@ -9,15 +9,15 @@
<b>Χρειαζόμαστε τη βοήθειά σας για να μεταφράσουμε αυτό το αρχείο README, το <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> και το <a href="https://github.com/rustdesk/doc.rustdesk.com">Doc</a> στη μητρική σας γλώσσα</b>
</p>
Επικοινωνήστε μαζί μας μέσω: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
Επικοινωνήστε μαζί μας μέσω: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-%CE%A0%CF%81%CE%BF%CE%B7%CE%B3%CE%BC%CE%AD%CE%BD%CE%B5%CF%82%20%CE%94%CF%85%CE%BD%CE%B1%CF%84%CF%8C%CF%84%CE%B7%CF%84%CE%B5%CF%82-blue)](https://rustdesk.com/pricing.html)
Ένα λογισμικό απομακρυσμένης επιφάνειας εργασίας, γραμμένο σε γλώσσα Rust. Δεν χρειάζεται κάποια παραμετροποίηση, λειτουργεί αμέσως μετά την εγκατάσταση. Έχετε τον πλήρη έλεγχο των δεδομένων σας, χωρίς να ανησυχείτε για την ασφάλειά τους. Μπορείτε να χρησιμοποιήσετε τους προκαθορισμένους διακομιστές rendezvous/αναμετάδοσης, [να εγκαταστήσετε τον δικό σας διακομιστή](https://rustdesk.com/server), ή [να αναπτύξετε ένα δικό σας διακομιστή rendezvous/αναμετάδοσης](https://github.com/rustdesk/rustdesk-server-demo).
![image](https://user-images.githubusercontent.com/71636191/171661982-430285f0-2e12-4b1d-9957-4a58e375304d.png)
Το RustDesk ενθαρρύνει τη συνεισφορά όλων. Διαβάστε το [`docs/CONTRIBUTING.md`](docs/CONTRIBUTING.md) για βοήθεια στο πως να ξεκινήσετε.
Το RustDesk ενθαρρύνει τη συνεισφορά όλων. Διαβάστε το [`docs/CONTRIBUTING.md`](CONTRIBUTING.md) για βοήθεια στο πως να ξεκινήσετε.
[**Συχνές ερωτήσεις**](https://github.com/rustdesk/rustdesk/wiki/FAQ)

View File

@@ -9,9 +9,9 @@
<b>Kell a segítséged, hogy lefordítsuk ezt a README-t, <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">a RustDesk UI-t</a> és a <a href="https://github.com/rustdesk/doc.rustdesk.com">Dokumentációt</a> az anyanyelvedre</b>
</p>
Beszélgess velünk: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
Beszélgess velünk: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-Speci%C3%A1lis%20Funkci%C3%B3k-blue)](https://rustdesk.com/pricing.html)
A RustDesk egy távoli elérésű asztali szoftver, Rust-ban írva. Működik mindenféle konfiguráció nélkül, feltelepítéssel, vagy anélkül. Az adataidat teljesen te kezeled, nincs szükség aggódásra a harmadik felek miatt. Használhatod a RustDesk punblikus randevú/relay szervereit, [hostolhatsz sajátot](https://rustdesk.com/server), vagy akár [írhatsz is egyet](https://github.com/rustdesk/rustdesk-server-demo).

View File

@@ -9,9 +9,9 @@
<b>Kami membutuhkan bantuanmu untuk menterjemahkan file README dan <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> ke Bahasa Indonesia</b>
</p>
Mari mengobrol bersama kami: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
Mari mengobrol bersama kami: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-Fitur%20Lanjutan-blue)](https://rustdesk.com/pricing.html)
[![Open Bounties](https://img.shields.io/endpoint?url=https%3A%2F%2Fconsole.algora.io%2Fapi%2Fshields%2Frustdesk%2Fbounties%3Fstatus%3Dopen)](https://console.algora.io/org/rustdesk/bounties?status=open)

View File

@@ -9,9 +9,9 @@
<b>Abbiamo bisogno del tuo aiuto per tradurre questo file README e la <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">UI RustDesk</a> nella tua lingua nativa</b>
</p>
Chatta con noi su: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
Chatta con noi su: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-Funzionalit%C3%A0%20Avanzate-blue)](https://rustdesk.com/pricing.html)
[![Bounties aperti](https://img.shields.io/endpoint?url=https%3A%2F%2Fconsole.algora.io%2Fapi%2Fshields%2Frustdesk%2Fbounties%3Fstatus%3Dopen)](https://console.algora.io/org/rustdesk/bounties?status=open)
@@ -164,6 +164,10 @@ Assicurati di eseguire questi comandi dalla radice del repository RustDesk, altr
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: codice Flutter per desktop e mobile
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: JavaScript per client web Flutter
> [!Attenzione]
> **Dichiarazione di non responsabilità per uso improprio:** <br>
> Gli sviluppatori di RustDesk non approvano né supportano alcun uso non etico o illegale di questo software. L'uso improprio, come l'accesso non autorizzato, il controllo o l'invasione della privacy, è strettamente contro le nostre linee guida. Gli autori non sono responsabili per qualsiasi uso improprio dell'applicazione.
## Schermate
![image](https://user-images.githubusercontent.com/71636191/113112362-ae4deb80-923b-11eb-957d-ff88daad4f06.png)

View File

@@ -5,20 +5,20 @@
<a href="#how-to-build-with-docker">Docker</a> •
<a href="#file-structure">Structure</a> •
<a href="#snapshot">Snapshot</a><br>
[<a href="docs/README-UA.md">Українська</a>] | [<a href="docs/README-CS.md">česky</a>] | [<a href="docs/README-ZH.md">中文</a>] | [<a href="docs/README-HU.md">Magyar</a>] | [<a href="docs/README-ES.md">Español</a>] | [<a href="docs/README-FA.md">فارسی</a>] | [<a href="docs/README-FR.md">Français</a>] | [<a href="docs/README-DE.md">Deutsch</a>] | [<a href="docs/README-PL.md">Polski</a>] | [<a href="docs/README-ID.md">Indonesian</a>] | [<a href="docs/README-FI.md">Suomi</a>] | [<a href="docs/README-ML.md">മലയാളം</a>] | [<a href="docs/README-JP.md">日本語</a>] | [<a href="docs/README-NL.md">Nederlands</a>] | [<a href="docs/README-IT.md">Italiano</a>] | [<a href="docs/README-RU.md">Русский</a>] | [<a href="docs/README-PTBR.md">Português (Brasil)</a>] | [<a href="docs/README-EO.md">Esperanto</a>] | [<a href="docs/README-KR.md">한국어</a>] | [<a href="docs/README-AR.md">العربي</a>] | [<a href="docs/README-VN.md">Tiếng Việt</a>] | [<a href="docs/README-DA.md">Dansk</a>] | [<a href="docs/README-GR.md">Ελληνικά</a>] | [<a href="docs/README-TR.md">Türkçe</a>]<br>
[<a href="README-UA.md">Українська</a>] | [<a href="README-CS.md">česky</a>] | [<a href="README-ZH.md">中文</a>] | [<a href="README-HU.md">Magyar</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FA.md">فارسی</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-ID.md">Indonesian</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>] | [<a href="README-KR.md">한국어</a>] | [<a href="README-AR.md">العربي</a>] | [<a href="README-VN.md">Tiếng Việt</a>] | [<a href="README-DA.md">Dansk</a>] | [<a href="README-GR.md">Ελληνικά</a>] | [<a href="README-TR.md">Türkçe</a>]<br>
<b>READMEや<a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a>、 <a href="https://github.com/rustdesk/doc.rustdesk.com">RustDesk Doc</a>の翻訳者を歓迎します!</b>
</p>
私たちと話す: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
私たちと話す: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-%E9%AB%98%E5%BA%A6%E3%81%AA%E6%A9%9F%E8%83%BD-blue)](https://rustdesk.com/pricing.html)
Rustで書かれた、設定不要ですぐに使えるリモートデスクトップソフトウェアです。自分のデータを完全にコントロールでき、セキュリティの心配もありません。私たちのランデブー/リレーサーバを使うことも、[自分でサーバーをセットアップする](https://rustdesk.com/server) ことも、 [自分でランデブー/リレーサーバを作成する](https://github.com/rustdesk/rustdesk-server-demo)こともできます。
![image](https://user-images.githubusercontent.com/71636191/171661982-430285f0-2e12-4b1d-9957-4a58e375304d.png)
RustDeskは皆さんの貢献を歓迎します。
貢献の方法については[CONTRIBUTING.md](docs/CONTRIBUTING.md)をご確認ください。
貢献の方法については[CONTRIBUTING.md](CONTRIBUTING.md)をご確認ください。
[**よくある質問**](https://github.com/rustdesk/rustdesk/wiki/FAQ)
@@ -168,6 +168,10 @@ target/release/rustdesk
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: デスクトップとモバイル向けのFlutterコード
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: Flutterウェブクライアント向けのJavaScript
> [!注意]
> **:不正使用に関する免責事項** <br>
> RustDeskの開発者は、このソフトウェアの非倫理的または違法な使用を容認または支持しません。不正アクセス、不正な制御、またはプライバシーの侵害などの不正使用は、当社のガイドラインに厳密に違反します。開発者は、アプリケーションの不正使用に対して一切の責任を負いません。
## スクリーンショット
![Connection Manager](https://github.com/rustdesk/rustdesk/assets/28412477/db82d4e7-c4bc-4823-8e6f-6af7eadf7651)

View File

@@ -1,64 +1,84 @@
<p align="center">
<img src="../res/logo-header.svg" alt="RustDesk - Your remote desktop"><br>
<a href="#free-public-servers">Servers</a> •
<a href="#raw-steps-to-build">Build</a> •
<a href="#how-to-build-with-docker">Docker</a> •
<a href="#file-structure">Structure</a> •
<a href="#snapshot">Snapshot</a><br>
[<a href="../README.md">English</a>] | [<a href="README-UA.md">Українська</a>] | [<a href="README-CS.md">česky</a>] | [<a href="README-ZH.md">中文</a>] | [<a href="README-HU.md">Magyar</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FA.md">فارسی</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-ID.md">Indonesian</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>] | [<a href="README-AR.md">العربي</a>] | [<a href="README-VN.md">Tiếng Việt</a>] | [<a href="README-GR.md">Ελληνικά</a>]<br>
<b>README를 모국어로 번역하기 위한 당신의 도움의 필요합니다.</b>
<a href="#빌드를_위한_원시_단계">빌드</a> •
<a href="#Docker로_빌드하는_방법">Docker</a> •
<a href="#파일_구조">구조</a> •
<a href="#스크린샷">스냅샷</a><br>
[<a href="../README.md">English</a>] | [<a href="README-UA.md">Українська</a>] | [<a href="README-CS.md">česky</a>] | [<a href="README-ZH.md">中文</a>] | [<a href="README-HU.md">Magyar</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FA.md">فارسی</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-ID.md">Indonesian</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>] | [<a href="README-KR.md">한국어</a>] | [<a href="README-AR.md">العربي</a>] | [<a href="README-VN.md">Tiếng Việt</a>] | [<a href="README-DA.md">Dansk</a>] | [<a href="README-GR.md">Ελληνικά</a>] | [<a href="README-TR.md">Türkçe</a>] | [<a href="README-NO.md">Norsk</a>] | [<a href="README-RO.md">Română</a>]<br>
<b>이 README, <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> 및 <a href="https://github.com/rustdesk/doc.rustdesk.com">RustDesk 문서</a>를 귀하의 모국어로 번역하는 데 도움이 필요합니다</b>
</p>
채팅하기: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
> [!Caution]
> **오용 면책 조항:** <br>
> RustDesk의 개발자는 이 소프트웨어의 비윤리적 또는 불법적인 사용을 묵인하거나 지원하지 않습니다. 무단 액세스, 제어 또는 개인정보 침해와 같은 오용은 엄격하게 당사의 지침에 위배됩니다. 작성자는 응용 프로그램의 오용에 대해 책임을 지지 않습니다.
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
우리와 채팅: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
Rust로 작성되었고, 설정없이 바로 사용할 수 있는 원격 데스트탑 소프트웨어입니다. 자신의 데이터를 완전히 컨트롤할 수 있고, 보안의 염려도 없습니다. 우리의 rendezvous/relay 서버를 사용해도, [직접 설정](https://rustdesk.com/server)하거나 [직접 rendezvous/relay 서버를 작성할 수도 있습니다](https://github.com/rustdesk/rustdesk-server-demo).
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-%EA%B3%A0%EA%B8%89%20%EA%B8%B0%EB%8A%A5-blue)](https://rustdesk.com/pricing.html)
또 하나의 원격 데스크톱 솔루션으로, Rust로 작성되었습니다. 별도의 설정 없이 바로 사용할 수 있습니다. 데이터에 대한 완전한 통제권을 가지며 보안에 대한 걱정이 없습니다. 저희 랑데부/릴레이 서버를 사용하거나, [직접 설정](https://rustdesk.com/server)하거나, [자신만의 랑데부/릴레이 서버를 작성](https://github.com/rustdesk/rustdesk-server-demo)할 수 있습니다.
![image](https://user-images.githubusercontent.com/71636191/171661982-430285f0-2e12-4b1d-9957-4a58e375304d.png)
RustDesk는 모든 기여를 환영합니다. 기여하고자 한다면 [`docs/CONTRIBUTING.md`](CONTRIBUTING.md)를 참조해주세요.
RustDesk는 모든 분들의 기여를 환영합니다. 시작하는 데 도움이 필요하면 [CONTRIBUTING-KR.md](CONTRIBUTING-KR.md)를 참조세요.
[**RustDesk는 어떻게 작동하는가?**](https://github.com/rustdesk/rustdesk/wiki/How-does-RustDesk-work%3F)
[**자주 묻는 질문**](https://github.com/rustdesk/rustdesk/wiki/FAQ)
[**BINARY DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
[**바이너리 다운로드**](https://github.com/rustdesk/rustdesk/releases)
## 의존관계
[**개발자 빌드**](https://github.com/rustdesk/rustdesk/releases/tag/nightly)
데스크탑판에는 GUI에 [sciter](https://sciter.com/)가 사용되었습니다. sciter dynamic library 를 다운로드해주세요.
[<img src="https://f-droid.org/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
[<img src="https://flathub.org/api/badge?svg&locale=en"
alt="Get it on Flathub"
height="80">](https://flathub.org/apps/com.rustdesk.RustDesk)
## 종속성
데스크톱 버전은 GUI로 Flutter 또는 Sciter (더 이상 지원되지 않음)를 사용하며, 이 자습서는 시작하기 더 쉽고 친숙한 Sciter 전용입니다. Flutter 버전 빌드는 [CI](https://github.com/rustdesk/rustdesk/blob/master/.github/workflows/flutter-build.yml)을 확인하세요.
Sciter 동적 라이브러리를 직접 다운로드하세요.
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
[MacOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
[macOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
모바일 버전은 Flutter를 사용합니다. 데스크탑 또한 Sciter에서 Flutter로 마이그레이션할 예정입니다.
## 빌드를_위한_원시_단계
## 빌드 순서
- Rust 개발 환경과 C++ 빌드 환경 준비
- Rust 개발환경, C++ 빌드 환경을 준비합니다.
- [vcpkg](https://github.com/microsoft/vcpkg) 설치하고 `VCPKG_ROOT` 환경변수를 정확히 설정합니다.
- [vcpkg](https://github.com/microsoft/vcpkg)를 설치하고 `VCPKG_ROOT` 환경 변수를 올바르게 설정합니다
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static aom:x64-windows-static
- Linux/MacOS: vcpkg install libvpx libyuv opus aom
- Linux/macOS: vcpkg install libvpx libyuv opus aom
- 실행 `cargo run`
- `cargo run` 실행
## [빌드](https://rustdesk.com/docs/en/dev/build/)
## Linux에서 빌드 순서
## Linux에서 빌드하는 방법
### Ubuntu 18 (Debian 10)
```sh
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev \
libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake make \
libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libpam0g-dev
```
### openSUSE Tumbleweed
```sh
sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel pam-devel
```
### Fedora 28 (CentOS 8)
```sh
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel pam-devel
```
### Arch (Manjaro)
@@ -79,7 +99,7 @@ export VCPKG_ROOT=$HOME/vcpkg
vcpkg/vcpkg install libvpx libyuv opus aom
```
### libvpx 수정 (For Fedora용)
### libvpx 수정 (Fedora용)
```sh
cd vcpkg/buildtrees/libvpx/src
@@ -97,7 +117,7 @@ cd
```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
git clone https://github.com/rustdesk/rustdesk
git clone --recurse-submodules https://github.com/rustdesk/rustdesk
cd rustdesk
mkdir -p target/debug
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
@@ -105,56 +125,58 @@ mv libsciter-gtk.so target/debug
VCPKG_ROOT=$HOME/vcpkg cargo run
```
## Docker빌드하는 방법
## Docker로_빌드하는_방법
리포지토리를 클론하고, Docker 컨테이너 구성하는 것으로 시작합니다.
먼저 리포지토리를 복제하고 Docker 컨테이너를 빌드합니다:
```sh
git clone https://github.com/rustdesk/rustdesk
cd rustdesk
git submodule update --init --recursive
docker build -t "rustdesk-builder" .
```
이후, 애플리케이션을 빌드할 필요가 있을 때마다, 아래의의 명령을 실행합니다.
그런 다음 응용 프로그램을 빌드해야 할 때마다 다음 명령을 실행합니다:
```sh
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
```
빌드에서는 의존관계가 캐시될 때까지 시간이 걸릴 수 있습니다만, 이후 빌드는 빨라집니다. 더불어 빌드 명령에 다른 인수를 지정할 필요가 있다면, 명령 끝에 있는 `<OPTIONAL-ARGS>` 지정할 수 있습니다. 예를 들어 최적화된 출시 버전을 빌드하고 싶다면 이렇게 상기한 명령 뒤에 `--release` 붙여 실행합니다. 성공했다면 실행파일은 시스템 타겟 폴더에 담겨지고, 다음 명령으로 실행할 수 있습니다.
번째 빌드는 종속성이 캐시되기까지 시간이 오래 걸릴 수 있으며, 이후 빌드는 빨라집니다. 또한 빌드 명령에 다른 인수를 지정해야 하는 경우 명령 끝 `<OPTIONAL-ARGS>` 위치에 인수를 지정할 수 있습니다. 예를 들어 최적화된 릴리스 버전을 빌드하려면 위의 명령 뒤에 `--release`추가하면 됩니다. 결과 실행 파일은 시스템의 대상 폴더에서 사용할 수 있으며 실행할 수 있습니다::
```sh
target/debug/rustdesk
```
혹은 출시용 실행 파일을 실행할 수도 있습니다.
또는 릴리스 실행 파일을 실행하는 경우:
```sh
target/release/rustdesk
```
명령을 RustDesk 리포지토리 루트에서 실행한다는 것을 확인해주세요. 그렇게 하지 않으면 애플리케이션이 필요한 리소스를 발견하지 못 가능성이 있습니다. 또한 `install`, `run` 같은 cargo 하위 명령은 호스트가 아니라 컨테이너 프로그램을 설치, 실행을 위함이므로 현재 이 방법 지원지 않다는 점념해주시길 바랍니다.
RustDesk 리포지토리 루트에서 이러한 명령을 실행하고 있는지 확인하세요. 그렇지 않으면 응용 프로그램이 필요한 리소스를 지 못할 있습니다. 또한 `install` 또는 `run` 같은 다른 cargo 하위 명령은 호스트가 아 컨테이너 내부에 프로그램을 설치하거나 실행하므로 현재 이 방법을 통해 지원지 않다는 점의하세요.
## 파일 구조
## 파일_구조
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: 비디오 코덱, 설정, tcp/udp 랩퍼, protobuf, 파일 전송을 위한 fs 함수, 그 외 유틸리티 함수
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: 화면 캡
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: 플랫폼 고유 키보드/마우스 컨트롤
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: GUI
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: 오디오, 클립보드, 입력, 비디오 서비스 그리고 네트워크 연결
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: 피어 접속 시작
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: [rustdesk-server](https://github.com/rustdesk/rustdesk-server)와 통신해서 리모트 다이렉트 (TCP hole punching) 혹은 relayed 접속
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: 플랫폼 고유의 코드
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: 모바일용 Flutter 코드
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: Flutter 웹 클라이언트용 자바스크립트
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: 비디오 코덱, 구성, tcp/udp wrapper, protobuf, 파일 전송을 위한 fs 함수 및 기타 유틸리티 함수
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: 화면 캡
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: 플랫폼 키보드/마우스 제어
- **[libs/clipboard](https://github.com/rustdesk/rustdesk/tree/master/libs/clipboard)**: Windows, Linux, macOS용 파일 복사 및 붙여넣기 구현
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: 더 이상 사용되지 않는 Sciter UI (지원 중단)
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: 오디오/클립보드/입력/비디오 서비스 및 네트워크 연결
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: 피어 연결 시작
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: [rustdesk-server](https://github.com/rustdesk/rustdesk-server)와 통신, 원격 다이렉트 (TCP 홀 펀칭) 또는 릴레이 연결 대기
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: 플랫폼별 코드
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: 데스크톱 및 모바일용 Flutter 코드
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/v1/js)**: Flutter 웹 클라이언트용 JavaScript
## 스
## 스크린
![image](https://user-images.githubusercontent.com/71636191/113112362-ae4deb80-923b-11eb-957d-ff88daad4f06.png)
![Connection Manager](https://github.com/rustdesk/rustdesk/assets/28412477/db82d4e7-c4bc-4823-8e6f-6af7eadf7651)
![image](https://user-images.githubusercontent.com/71636191/113112619-f705a480-923b-11eb-911d-97e984ef52b6.png)
![Connected to a Windows PC](https://github.com/rustdesk/rustdesk/assets/28412477/9baa91e9-3362-4d06-aa1a-7518edcbd7ea)
![image](https://user-images.githubusercontent.com/71636191/113112857-3fbd5d80-923c-11eb-9836-768325faf906.png)
![File Transfer](https://github.com/rustdesk/rustdesk/assets/28412477/39511ad3-aa9a-4f8c-8947-1cce286a46ad)
![image](https://user-images.githubusercontent.com/71636191/135385039-38fdbd72-379a-422d-b97f-33df71fb1cec.png)
![TCP Tunneling](https://github.com/rustdesk/rustdesk/assets/28412477/78e8708f-e87e-4570-8373-1360033ea6c5)

View File

@@ -9,9 +9,9 @@
<b>ഈ README നിങ്ങളുടെ മാതൃഭാഷയിലേക്ക് വിവർത്തനം ചെയ്യാൻ ഞങ്ങൾക്ക് നിങ്ങളുടെ സഹായം ആവശ്യമാണ്</b>
</p>
ഞങ്ങളുമായി ചാറ്റ് ചെയ്യുക: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
ഞങ്ങളുമായി ചാറ്റ് ചെയ്യുക: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-%E0%B4%B5%E0%B4%BF%E0%B4%95%E0%B4%B8%E0%B4%BF%E0%B4%A4%20%E0%B4%B8%E0%B4%B5%E0%B4%BF%E0%B4%B6%E0%B5%87%E0%B4%B7%E0%B4%A4%E0%B4%95%E0%B5%BE-blue)](https://rustdesk.com/pricing.html)
റസ്റ്റിൽ എഴുതിയ മറ്റൊരു റിമോട്ട് ഡെസ്ക്ടോപ്പ് സോഫ്റ്റ്‌വെയർ. ബോക്‌സിന് പുറത്ത് പ്രവർത്തിക്കുന്നു, കോൺഫിഗറേഷൻ ആവശ്യമില്ല. സുരക്ഷയെക്കുറിച്ച് ആശങ്കകളൊന്നുമില്ലാതെ, നിങ്ങളുടെ ഡാറ്റയുടെ പൂർണ്ണ നിയന്ത്രണം നിങ്ങൾക്കുണ്ട്. നിങ്ങൾക്ക് ഞങ്ങളുടെ rendezvous/relay സെർവർ ഉപയോഗിക്കാം, [സ്വന്തമായി സജ്ജീകരിക്കുക](https://rustdesk.com/server), അല്ലെങ്കിൽ [നിങ്ങളുടെ സ്വന്തം rendezvous/relay സെർവർ എഴുതുക](https://github.com/rustdesk/rustdesk-server-demo).

View File

@@ -9,9 +9,9 @@
<b>Wij hebben uw hulp nodig om dit README bestand te vertalen, <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> en <a href="https://github.com/rustdesk/doc.rustdesk.com">Doc</a> naar uw moedertaal</b>
</p>
Chat met ons: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
Chat met ons: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-Geavanceerde%20Functies-blue)](https://rustdesk.com/pricing.html)
Alweer een andere programma voor -bureaublad op afstand-, geschreven in Rust. Werkt -out of the box-, geen configuratie nodig. U heeft volledige controle over uw gegevens, en hoeft zich geen zorgen te maken over de beveiliging. U kunt onze rendez-vous/relay server gebruiken, [je eigen server opzetten](https://rustdesk.com/blog/id-relay-set), of [je eigen rendez-vous/relay-server schrijven](https://github.com/rustdesk/rustdesk-server-demo).

177
docs/README-NO.md Normal file
View File

@@ -0,0 +1,177 @@
<p align="center">
<img src="res/logo-header.svg" alt="RustDesk - Your remote desktop"><br>
<a href="#public-servers">Servere</a> •
<a href="#raw-steps-to-build">Build</a> •
<a href="#how-to-build-with-docker">Docker</a> •
<a href="#file-structure">Struktur</a> •
<a href="#snapshot">Snapshot</a><br>
[<a href="docs/README-UA.md">Українська</a>] | [<a href="docs/README-CS.md">česky</a>] | [<a href="docs/README-ZH.md">中文</a>] | [<a href="docs/README-HU.md">Magyar</a>] | [<a href="docs/README-ES.md">Español</a>] | [<a href="docs/README-FA.md">فارسی</a>] | [<a href="docs/README-FR.md">Français</a>] | [<a href="docs/README-DE.md">Deutsch</a>] | [<a href="docs/README-PL.md">Polski</a>] | [<a href="docs/README-ID.md">Indonesian</a>] | [<a href="docs/README-FI.md">Suomi</a>] | [<a href="docs/README-ML.md">മലയാളം</a>] | [<a href="docs/README-JP.md">日本語</a>] | [<a href="docs/README-NL.md">Nederlands</a>] | [<a href="docs/README-IT.md">Italiano</a>] | [<a href="docs/README-RU.md">Русский</a>] | [<a href="docs/README-PTBR.md">Português (Brasil)</a>] | [<a href="docs/README-EO.md">Esperanto</a>] | [<a href="docs/README-KR.md">한국어</a>] | [<a href="docs/README-AR.md">العربي</a>] | [<a href="docs/README-VN.md">Tiếng Việt</a>] | [<a href="docs/README-DA.md">Dansk</a>] | [<a href="docs/README-GR.md">Ελληνικά</a>] | [<a href="docs/README-TR.md">Türkçe</a>] | [<a href="docs/README-NO.md">Norsk</a><br>
<b>Vi trenger din hjelp til å oversette denne README-en, <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> og <a href="https://github.com/rustdesk/doc.rustdesk.com">RustDesk Doc</a> tid ditt morsmål</b>
</p>
Snakk med oss: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-Avanserte%20Funksjoner-blue)](https://rustdesk.com/pricing.html)
Enda en annen fjernstyrt desktop programvare, skrevet i Rust. Virker rett ut av pakken, ingen konfigurasjon nødvendig. Du har full kontroll over din data, uten beskymring for sikkerhet. Du kan bruke vår rendezvous_mediator/relay server, [sett opp din egen](https://rustdesk.com/server), eller [skriv din egen rendezvous_mediator/relay server](https://github.com/rustdesk/rustdesk-server-demo).
![image](https://user-images.githubusercontent.com/71636191/171661982-430285f0-2e12-4b1d-9957-4a58e375304d.png)
RustDesk er velkommen for bidrag fra alle. Se [CONTRIBUTING.md](CONTRIBUTING-NO.md) for hjelp med oppstart.
[**FAQ**](https://github.com/rustdesk/rustdesk/wiki/FAQ)
[**BINARY NEDLASTING**](https://github.com/rustdesk/rustdesk/releases)
[**NIGHTLY BUILD**](https://github.com/rustdesk/rustdesk/releases/tag/nightly)
[<img src="https://f-droid.org/badge/get-it-on.png"
alt="Få det på F-Droid"
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
[<img src="https://flathub.org/api/badge?svg&locale=en"
alt="Få det på Flathub"
height="80">](https://flathub.org/apps/com.rustdesk.RustDesk)
## Avhengigheter
Desktop versjoner bruker Flutter eller Sciter (avviklet) for GUI, denne veiledningen er bare for Sciter, grunnet att det er letter og en mer venlig start. Skjekk ut vår [CI](https://github.com/rustdesk/rustdesk/blob/master/.github/workflows/flutter-build.yml) for bygging av Flutter versjonen.
Venligst last ned Sciters dynamiske bibliotek selv.
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
[macOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
## Rå steg for bygging
- Klargjør ditt Rust development env og C++ build env
- Installer [vcpkg](https://github.com/microsoft/vcpkg), og koriger `VCPKG_ROOT` env vaiabelen
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static aom:x64-windows-static
- Linux/macOS: vcpkg install libvpx libyuv opus aom
- Kjør `cargo run`
## [Bygg](https://rustdesk.com/docs/en/dev/build/)
## Hvordan Bygge til Linux
### Ubuntu 18 (Debian 10)
```sh
sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev \
libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake make \
libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libpam0g-dev
```
### openSUSE Tumbleweed
```sh
sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel pam-devel
```
### Fedora 28 (CentOS 8)
```sh
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel pam-devel
```
### Arch (Manjaro)
```sh
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pipewire
```
### Installer vcpkg
```sh
git clone https://github.com/microsoft/vcpkg
cd vcpkg
git checkout 2023.04.15
cd ..
vcpkg/bootstrap-vcpkg.sh
export VCPKG_ROOT=$HOME/vcpkg
vcpkg/vcpkg install libvpx libyuv opus aom
```
### Fiks libvpx (For Fedora)
```sh
cd vcpkg/buildtrees/libvpx/src
cd *
./configure
sed -i 's/CFLAGS+=-I/CFLAGS+=-fPIC -I/g' Makefile
sed -i 's/CXXFLAGS+=-I/CXXFLAGS+=-fPIC -I/g' Makefile
make
cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
cd
```
### Bygg
```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
git clone https://github.com/rustdesk/rustdesk
cd rustdesk
mkdir -p target/debug
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
mv libsciter-gtk.so target/debug
VCPKG_ROOT=$HOME/vcpkg cargo run
```
## Hvordan bygge med Docker
Start med å klone repositoret og bygg Docker konteineren:
```sh
git clone https://github.com/rustdesk/rustdesk
cd rustdesk
docker build -t "rustdesk-builder" .
```
Deretter, hver gang du trenger å bygge applikasjonen, kjør følgene kommando:
```sh
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
```
Det kan ta lengere tid før avhengighetene blir bufret første gang du bygger, senere bygg er raskere. Hvis du trenger å spesifisere forkjellige argumenter til bygge kommandoen, kan du gjøre det på slutten av kommandoen ved `<OPTIONAL-ARGS>` feltet. For eksempel, hvis du ville bygge en optimalisert release versjon, ville du kjørt kommandoen over fulgt `--release`. Den kjørbare filen vill være tilgjengelig i mål direktive på ditt system, og kan bli kjørt med:
```sh
target/debug/rustdesk
```
Eller, hvis du kjører ett release program:
```sh
target/release/rustdesk
```
Venligst pass på att du kjører disse kommandoene fra roten av RustDesk repositoret, eller kan det hende att applikasjon ikke finner de riktige ressursene. Pass også på att andre cargo subkommandoer som for eksempel `install` eller `run` ikke støttes med denne metoden da de vill installere eller kjøre programmet i konteineren istedet for verten.
## Fil Struktur
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video kodek, configurasjon, tcp/udp innpakning, protobuf, fs funksjon for fil overføring, og noen andre verktøy funksjoner
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: skjermfangst
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: platform spesefik keyboard/mus kontroll
- **[libs/clipboard](https://github.com/rustdesk/rustdesk/tree/master/libs/clipboard)**: fil kopi og innliming implementasjon for Windows, Linux, macOS.
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: foreldret Sciter UI (avviklet)
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: lyd/utklippstavle/input/video tjenester, og internett tilkobling
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: start en peer tilkobling
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Kommunikasjon med [rustdesk-server](https://github.com/rustdesk/rustdesk-server), vent på direkte fjernstyring (TCP hulling) eller vidresendt tilkobling
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: platform spesefik kode
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: Flutter kode for desktop og mobil
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: JavaScript for Flutter nettsted klient
## Skjermbilder
![Tilkoblings Manager](https://github.com/rustdesk/rustdesk/assets/28412477/db82d4e7-c4bc-4823-8e6f-6af7eadf7651)
![Koble til Windows PC](https://github.com/rustdesk/rustdesk/assets/28412477/9baa91e9-3362-4d06-aa1a-7518edcbd7ea)
![Fil Overføring](https://github.com/rustdesk/rustdesk/assets/28412477/39511ad3-aa9a-4f8c-8947-1cce286a46ad)
![TCP Tunneling](https://github.com/rustdesk/rustdesk/assets/28412477/78e8708f-e87e-4570-8373-1360033ea6c5)

View File

@@ -9,11 +9,13 @@
<b>Potrzebujemy twojej pomocy w tłumaczeniu README na twój ojczysty język</b>
</p>
Porozmawiaj z nami na: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
Porozmawiaj z nami na: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-Zaawansowane%20Funkcje-blue)](https://rustdesk.com/pricing.html)
Kolejny program do zdalnego pulpitu, napisany w Rust. Działa od samego początku, nie wymaga konfiguracji. Masz pełną kontrolę nad swoimi danymi, bez obaw o bezpieczeństwo. Możesz skorzystać z naszego darmowego serwera publicznego, [skonfigurować własny](https://rustdesk.com/server), lub [napisać własny serwer](https://github.com/rustdesk/rustdesk-server-demo).
## O projekcie
RustDesk to wieloplatformowe oprogramowanie do zdalnego pulpitu, napisane w języku Rust, zaprojektowane z myślą o prostocie wdrożenia, bezpieczeństwie i pełnej kontroli użytkownika nad danymi. Aplikacja działa od razu po uruchomieniu i nie wymaga skomplikowanej konfiguracji. Możesz skorzystać z naszego darmowego serwera publicznego, [skonfigurować własny](https://rustdesk.com/server), lub [napisać własny serwer](https://github.com/rustdesk/rustdesk-server-demo).
![image](https://user-images.githubusercontent.com/71636191/171661982-430285f0-2e12-4b1d-9957-4a58e375304d.png)
@@ -31,7 +33,7 @@ RustDesk zaprasza do współpracy każdego. Zobacz [`docs/CONTRIBUTING-PL.md`](C
## Zależności
Wersje desktopowe używają [sciter](https://sciter.com/) dla GUI, proszę pobrać samodzielnie bibliotekę sciter.
Wersje desktopowe korzystają z biblioteki [sciter](https://sciter.com/) jako silnika GUI. Bibliotekę Sciter należy pobrać i zainstalować samodzielnie.
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
@@ -165,6 +167,3 @@ Upewnij się, że uruchamiasz te polecenia z katalogu głównego repozytorium Ru
![image](https://user-images.githubusercontent.com/71636191/135385039-38fdbd72-379a-422d-b97f-33df71fb1cec.png)
## [Serwery publiczne](#public-servers)
RustDesk jest obsługiwany przez bezpłatne serwer w Unii Europejskiej, uprzejmie dostarczony przez [Codext GmbH](https://codext.link/rustdesk?utm_source=github)

View File

@@ -1,55 +1,82 @@
<p align="center">
<img src="../res/logo-header.svg" alt="RustDesk - Seu desktop remoto"><br>
<a href="#servidores-públicos-grátis">Servidores</a> •
<a href="#compilação-crua">Compilar</a> •
<a href="#como-compilar-com-docker">Docker</a> •
<a href="#compilar">Compilar</a> •
<a href="#como-compilar-com-o-docker">Docker</a> •
<a href="#estrutura-de-arquivos">Estrutura</a> •
<a href="#screenshots">Screenshots</a><br>
[<a href="../README.md">English</a>] | [<a href="README-UA.md">Українська</a>] | [<a href="README-CS.md">česky</a>] | [<a href="README-ZH.md">中文</a>] | [<a href="README-HU.md">Magyar</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FA.md">فارسی</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-ID.md">Indonesian</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-EO.md">Esperanto</a>] | [<a href="README-KR.md">한국어</a>] | [<a href="README-AR.md">العربي</a>] | [<a href="README-VN.md">Tiếng Việt</a>] | [<a href="README-GR.md">Ελληνικά</a>]<br>
<b>Precisamos de sua ajuda para traduzir este README e a <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">UI do RustDesk</a> para sua língua nativa</b>
<a href="#capturas-de-tela">Capturas de Tela</a><br>
[<a href="../README.md">Inglês</a>] | [<a href="docs/README-UA.md">Ucraniano</a>] | [<a href="docs/README-CS.md">Tcheco</a>] | [<a href="docs/README-ZH.md">Chinês</a>] | [<a href="docs/README-HU.md">Húngaro</a>] | [<a href="docs/README-ES.md">Espanhol</a>] | [<a href="docs/README-FA.md">Persa</a>] | [<a href="docs/README-FR.md">Frans</a>] | [<a href="docs/README-DE.md">Alemão</a>] | [<a href="docs/README-PL.md">Polonês</a>] | [<a href="docs/README-ID.md">Indonésio</a>] | [<a href="docs/README-FI.md">Finlandês</a>] | [<a href="docs/README-ML.md">Malaiala</a>] | [<a href="docs/README-JP.md">Japonês</a>] | [<a href="docs/README-NL.md">Holandês</a>] | [<a href="docs/README-IT.md">Italiano</a>] | [<a href="docs/README-RU.md">Russo</a>] | [<a href="docs/README-EO.md">Esperanto</a>] | [<a href="docs/README-KR.md">Coreano</a>] | [<a href="docs/README-AR.md">Árabe</a>] | [<a href="docs/README-VN.md">Vietnamita</a>] | [<a href="docs/README-DA.md">Dinamarquês</a>] | [<a href="docs/README-GR.md">Grego</a>] | [<a href="docs/README-TR.md">Turco</a>] | [<a href="docs/README-NO.md">Norueguês</a>] | [<a href="docs/README-RO.md">Romeno</a>]<br>
<b>Precisamos da sua ajuda para traduzir este README, a <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">Interface do RustDesk</a> e a <a href="https://github.com/rustdesk/doc.rustdesk.com">Documentação do RustDesk</a> para o seu idioma nativo</b>
</p>
Converse conosco: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
> [!Caution]
> **Aviso de Isenção de Responsabilidade por Uso Indevido:** <br>
> Os desenvolvedores do RustDesk não toleram ou apoiam qualquer uso antiético ou ilegal deste software. O uso indevido, como acesso não autorizado, controle ou invasão de privacidade, viola estritamente nossas diretrizes. Os autores não são responsáveis por qualquer uso indevido do aplicativo.
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
Mais um software de desktop remoto, escrito em Rust. Funciona por padrão, sem necessidade de configuração. Você tem completo controle de seus dados, sem se preocupar com segurança. Você pode usar nossos servidores de rendezvous/relay, [configurar seu próprio](https://rustdesk.com/server), ou [escrever seu próprio servidor de rendezvous/relay](https://github.com/rustdesk/rustdesk-server-demo).
Converse conosco: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
RustDesk acolhe contribuições de todos. Leia [`docs/CONTRIBUTING.md`](CONTRIBUTING.md) para ver como começar.
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-Advanced%20Features-blue)](https://rustdesk.com/pricing.html)
[**DOWNLOAD DE BINÁRIOS**](https://github.com/rustdesk/rustdesk/releases)
Mais uma solução de desktop remoto, escrita em Rust. Funciona imediatamente, sem necessidade de configuração. Você tem controle total dos seus dados, sem preocupações com segurança. Você pode usar nosso servidor de conexão/retransmissão (rendezvous/relay), [configurar o seu próprio](https://rustdesk.com/server) ou [escrever seu próprio servidor de conexão/retransmissão](https://github.com/rustdesk/rustdesk-server-demo).
![image](https://user-images.githubusercontent.com/71636191/171661982-430285f0-2e12-4b1d-9957-4a58e375304d.png)
O RustDesk acolhe a contribuição de todos. Veja [CONTRIBUTING.md](docs/CONTRIBUTING.md) para ajuda em como começar.
[**Perguntas Frequentes (FAQ)**](https://github.com/rustdesk/rustdesk/wiki/FAQ)
[**DOWNLOAD DOS BINÁRIOS**](https://github.com/rustdesk/rustdesk/releases)
[**VERSÕES NIGHTLY (EM DESENVOLVIMENTO)**](https://github.com/rustdesk/rustdesk/releases/tag/nightly)
[<img src="https://f-droid.org/badge/get-it-on.png"
alt="Baixe no F-Droid"
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
[<img src="https://flathub.org/api/badge?svg&locale=en"
alt="Baixe no Flathub"
height="80">](https://flathub.org/apps/com.rustdesk.RustDesk)
## Dependências
Versões de desktop utilizam [sciter](https://sciter.com/) para a GUI, por favor baixe a biblioteca dinâmica sciter por conta própria.
As versões de desktop usam Flutter ou Sciter (descontinuado) para a interface gráfica (GUI). Este tutorial é apenas para o Sciter, por ser mais fácil e amigável para começar. Verifique nosso [CI](https://github.com/rustdesk/rustdesk/blob/master/.github/workflows/flutter-build.yml) para instruções de compilação da versão em Flutter.
Por favor, faça o download da biblioteca dinâmica do Sciter por conta própria.
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
[MacOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
[macOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
## Compilação crua
## Passos básicos para compilar
- Prepare seu ambiente de desenvolvimento Rust e ambiente de compilação C++
- Prepare seu ambiente de desenvolvimento Rust e o ambiente de compilação C++
- Instale [vcpkg](https://github.com/microsoft/vcpkg), e configure a variável de ambiente `VCPKG_ROOT` corretamente
- Instale o [vcpkg](https://github.com/microsoft/vcpkg) e configure a variável de ambiente `VCPKG_ROOT` corretamente
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static aom:x64-windows-static
- Linux/MacOS: vcpkg install libvpx libyuv opus aom
- Windows: `vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static aom:x64-windows-static`
- Linux/macOS: `vcpkg install libvpx libyuv opus aom`
- Execute `cargo run`
## Como compilar no Linux
## [Compilar](https://rustdesk.com/docs/en/dev/build/)
## Como Compilar no Linux
### Ubuntu 18 (Debian 10)
```sh
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake make libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libpam0g-dev
```
### openSUSE Tumbleweed
```sh
sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel pam-devel
```
### Fedora 28 (CentOS 8)
```sh
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel pam-devel
```
### Arch (Manjaro)
@@ -58,7 +85,7 @@ sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pipewire
```
### Instale vcpkg
### Instalar o vcpkg
```sh
git clone https://github.com/microsoft/vcpkg
@@ -70,7 +97,7 @@ export VCPKG_ROOT=$HOME/vcpkg
vcpkg/vcpkg install libvpx libyuv opus aom
```
### Conserte libvpx (Para o Fedora)
### Corrigir o libvpx (Para Fedora)
```sh
cd vcpkg/buildtrees/libvpx/src
@@ -83,12 +110,12 @@ cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
cd
```
### Compile
### Compilar
```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
git clone https://github.com/rustdesk/rustdesk
git clone --recurse-submodules https://github.com/rustdesk/rustdesk
cd rustdesk
mkdir -p target/debug
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
@@ -96,53 +123,57 @@ mv libsciter-gtk.so target/debug
VCPKG_ROOT=$HOME/vcpkg cargo run
```
## Como compilar com Docker
## Como compilar com o Docker
Comece clonando o repositório e montando o container docker:
Comece clonando o repositório e construindo o contêiner Docker:
```sh
git clone https://github.com/rustdesk/rustdesk
cd rustdesk
git submodule update --init --recursive
docker build -t "rustdesk-builder" .
```
Então, sempre que precisar compilar a aplicação, execute este comando:
Depois, cada vez que precisar compilar o aplicativo, execute o seguinte comando:
```sh
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
```
Note que a primeira compilação pode demorar mais antes que as dependências sejam armazenadas em cache, as compilações subsequentes serão mais rápidas. Adicionalmente, se você precisar especificar argumentos diferentes para o comando de compilação, você pode fazê-lo ao final do comando na posição do `<OPTIONAL-ARGS>`. Por exemplo, se você gostaria de compilar uma versão de release otimizada, você executaria o comando acima seguido de `--release`. O executável gerado estará disponível no diretório alvo no seu sistema, e pode ser executado com:
Note que a primeira compilação pode demorar mais a que as dependências sejam armazenadas em cache; as compilações subsequentes serão mais rápidas. Além disso, se você precisar especificar argumentos diferentes para o comando de compilação, pode fazê-lo ao final do comando na posição `<ARGUMENTOS-OPCIONAIS>`. Por exemplo, se você quiser compilar uma versão de lançamento (release) otimizada, executaria o comando acima seguido de `--release`. O executável resultante estará disponível na pasta `target` do seu sistema e pode ser executado com:
```sh
target/debug/rustdesk
```
Ou, se estiver rodando um executável de release:
Ou, se estiver executando o executável de lançamento:
```sh
target/release/rustdesk
```
Por favor verifique que está executando estes comandos da raiz do repositório do RustDesk, senão a aplicação pode não encontrar os recursos necessários. Note também que outros subcomandos do cargo como `install` ou `run` não são suportados atualmente via este método, já que eles iriam instalar ou rodar o programa dentro do container ao invés do host.
Certifique-se de executar esses comandos a partir da raiz do repositório do RustDesk, do contrário o aplicativo pode não encontrar os recursos necessários. Note também que outros subcomandos do cargo, como `install` ou `run`, não são suportados atualmente por este método, pois instalariam ou executariam o programa dentro do contêiner em vez de no sistema hospedeiro.
## Estrutura de arquivos
## Estrutura de Arquivos
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: codec de vídeo, configurações, wrapper de tcp/udp, protobuf, funções de sistema de arquivos para transferência de arquivos, e outras funções utilitárias
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: captura de tela
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: controle de teclado/mouse específico a cada plataforma
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: GUI
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: serviços de áudio/área de transferência/entrada/vídeo, e conexões de rede
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: iniciar uma conexão "peer to peer"
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Comunicação com [rustdesk-server](https://github.com/rustdesk/rustdesk-server), aguardar pela conexão remota direta (TCP hole punching) ou conexão indireta (relayed)
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: código específico a cada plataforma
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: codec de vídeo, configuração, encapsulador (wrapper) tcp/udp, protobuf, funções de sistema de arquivos para transferência de arquivos e algumas outras funções utilitárias.
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: captura de tela.
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: controle de teclado/mouse específico de cada plataforma.
- **[libs/clipboard](https://github.com/rustdesk/rustdesk/tree/master/libs/clipboard)**: implementação de copiar e colar arquivos para Windows, Linux e macOS.
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: interface Sciter antiga (descontinuada).
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: serviços de áudio/área de transferência/entrada/vídeo e conexões de rede.
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: inicia uma conexão direta (peer connection).
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Comunica-se com o [rustdesk-server](https://github.com/rustdesk/rustdesk-server), aguarda por conexão remota direta (perfuração de túnel TCP / hole punching) ou retransmitida.
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: código específico de cada plataforma.
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: código Flutter para desktop e dispositivos móveis.
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/v1/js)**: JavaScript para o cliente web do Flutter.
## Screenshots
## Capturas de Tela
![image](https://user-images.githubusercontent.com/71636191/113112362-ae4deb80-923b-11eb-957d-ff88daad4f06.png)
![Gerenciador de Conexões](https://github.com/rustdesk/rustdesk/assets/28412477/db82d4e7-c4bc-4823-8e6f-6af7eadf7651)
![image](https://user-images.githubusercontent.com/71636191/113112619-f705a480-923b-11eb-911d-97e984ef52b6.png)
![Conectado a um PC Windows](https://github.com/rustdesk/rustdesk/assets/28412477/9baa91e9-3362-4d06-aa1a-7518edcbd7ea)
![image](https://user-images.githubusercontent.com/71636191/113112857-3fbd5d80-923c-11eb-9836-768325faf906.png)
![Transferência de Arquivos](https://github.com/rustdesk/rustdesk/assets/28412477/39511ad3-aa9a-4f8c-8947-1cce286a46ad)
![image](https://user-images.githubusercontent.com/71636191/135385039-38fdbd72-379a-422d-b97f-33df71fb1cec.png)
![Tunelamento TCP](https://github.com/rustdesk/rustdesk/assets/28412477/78e8708f-e87e-4570-8373-1360033ea6c5)

181
docs/README-RO.md Normal file
View File

@@ -0,0 +1,181 @@
<p align="center">
<img src="../res/logo-header.svg" alt="RustDesk - desktopul tău la distanță"><br>
<a href="../README.md#raw-steps-to-build">Construire</a> •
<a href="../README.md#how-to-build-with-docker">Docker</a> •
<a href="../README.md#file-structure">Structură</a> •
<a href="../README.md#snapshot">Capturi</a><br>
[<a href="README-UA.md">Українська</a>] | [<a href="README-CS.md">česky</a>] | [<a href="README-ZH.md">中文</a>] | [<a href="README-HU.md">Magyar</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FA.md">فارسی</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-ID.md">Indonesian</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>] | [<a href="README-KR.md">한국어</a>] | [<a href="README-AR.md">العربي</a>] | [<a href="README-VN.md">Tiếng Việt</a>] | [<a href="README-DA.md">Dansk</a>] | [<a href="README-GR.md">Ελληνικά</a>] | [<a href="README-TR.md">Türkçe</a>] | [<a href="README-NO.md">Norsk</a>] | [<a href="README-RO.md">Română</a>]<br>
<b>Avem nevoie de ajutorul tău pentru a traduce acest README, <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> și <a href="https://github.com/rustdesk/doc.rustdesk.com">RustDesk Doc</a> în limba ta maternă</b>
</p>
> [!Atenție]
> **Declinare de responsabilitate privind utilizarea abuzivă:** <br>
> Dezvoltatorii RustDesk nu susțin sau aprobă utilizarea neetică sau ilegală a acestui software. Utilizarea abuzivă, cum ar fi accesul neautorizat, controlul sau invadarea intimității, este strict împotriva regulilor noastre. Autorii nu sunt responsabili pentru utilizarea necorespunzătoare a aplicației.
Conversați cu noi: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-Advanced%20Features-blue)](https://rustdesk.com/pricing.html)
Încă o soluție de desktop la distanță scrisă în Rust. Funcționează imediat, fără configurare necesară. Ai control total asupra datelor tale, fără probleme de securitate. Poți folosi serverul nostru de rendezvous/relay, [să-ți configurezi propriul server](https://rustdesk.com/server) sau [să scrii propriul server de rendezvous/relay](https://github.com/rustdesk/rustdesk-server-demo).
![imagine](https://user-images.githubusercontent.com/71636191/171661982-430285f0-2e12-4b1d-9957-4a58e375304d.png)
RustDesk primește contribuții de la oricine. Vezi [CONTRIBUTING.md](../docs/CONTRIBUTING.md) pentru ajutor la început.
[**ÎNTREBĂRI FRECVENTE (FAQ)**](https://github.com/rustdesk/rustdesk/wiki/FAQ)
[**DESCĂRCARE BINARE**](https://github.com/rustdesk/rustdesk/releases)
[**BUILD NIGHTLY**](https://github.com/rustdesk/rustdesk/releases/tag/nightly)
[<img src="https://f-droid.org/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
[<img src="https://flathub.org/api/badge?svg&locale=en"
alt="Get it on Flathub"
height="80">](https://flathub.org/apps/com.rustdesk.RustDesk)
## Dependențe
Versiunile desktop folosesc Flutter sau Sciter (depreciat) pentru interfață; acest ghid este pentru Sciter doar, deoarece este mai ușor și mai prietenos pentru început. Vezi [CI](https://github.com/rustdesk/rustdesk/blob/master/.github/workflows/flutter-build.yml) pentru construire cu Flutter.
Te rugăm să descarci singur librăria dinamică Sciter.
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
[macOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
## Pași pentru construire (Raw Steps to build)
- Pregătește mediul de dezvoltare Rust și mediul de construire C++
- Instalează [vcpkg](https://github.com/microsoft/vcpkg) și setează corect variabila de mediu `VCPKG_ROOT`
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static aom:x64-windows-static
- Linux/macOS: vcpkg install libvpx libyuv opus aom
- rulează `cargo run`
## [Construire](https://rustdesk.com/docs/en/dev/build/)
## Cum se construiește pe Linux
### Ubuntu 18 (Debian 10)
```sh
sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev \
libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake make \
libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libpam0g-dev
```
### openSUSE Tumbleweed
```sh
sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel pam-devel
```
### Fedora 28 (CentOS 8)
```sh
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel pam-devel
```
### Arch (Manjaro)
```sh
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pipewire
```
### Instalează vcpkg
```sh
git clone https://github.com/microsoft/vcpkg
cd vcpkg
git checkout 2023.04.15
cd ..
vcpkg/bootstrap-vcpkg.sh
export VCPKG_ROOT=$HOME/vcpkg
vcpkg/vcpkg install libvpx libyuv opus aom
```
### Repară libvpx (Pentru Fedora)
```sh
cd vcpkg/buildtrees/libvpx/src
cd *
./configure
sed -i 's/CFLAGS+=-I/CFLAGS+=-fPIC -I/g' Makefile
sed -i 's/CXXFLAGS+=-I/CXXFLAGS+=-fPIC -I/g' Makefile
make
cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
cd
```
### Build
```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
git clone --recurse-submodules https://github.com/rustdesk/rustdesk
cd rustdesk
mkdir -p target/debug
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
mv libsciter-gtk.so target/debug
VCPKG_ROOT=$HOME/vcpkg cargo run
```
## Cum să construiești cu Docker
Începe prin clonarea repository-ului și construirea imaginii Docker:
```sh
git clone https://github.com/rustdesk/rustdesk
cd rustdesk
git submodule update --init --recursive
docker build -t "rustdesk-builder" .
```
Apoi, de fiecare dată când trebuie să construiești aplicația, rulează comanda următoare:
```sh
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
```
Reține că prima construire poate dura mai mult până când dependențele sunt în cache; construirile ulterioare vor fi mai rapide. De asemenea, dacă trebuie să specifici argumente diferite comenzii de build, le poți adăuga la finalul comenzii în poziția `<OPTIONAL-ARGS>`. De exemplu, pentru a construi o versiune optimizată de release, adaugă `--release`. Executabilul rezultat va fi disponibil în folderul `target` pe sistemul tău, și poate fi rulat cu:
```sh
target/debug/rustdesk
```
Sau, dacă rulezi un executabil release:
```sh
target/release/rustdesk
```
Asigură-te că rulezi aceste comenzi din rădăcina repository-ului RustDesk, altfel aplicația poate să nu găsească resursele necesare. De asemenea, reține că alte subcomenzi cargo, cum ar fi `install` sau `run`, nu sunt acceptate în prezent prin această metodă, deoarece ar instala sau rula programul în interiorul containerului în loc de gazdă.
## Structura fișierelor
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: codec video, config, wrapper tcp/udp, protobuf, funcții fs pentru transfer de fișiere și alte funcții utilitare
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: capturare ecran
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: control tastatură/mouse specific platformei
- **[libs/clipboard](https://github.com/rustdesk/rustdesk/tree/master/libs/clipboard)**: implementare copy/paste pentru fișiere pentru Windows, Linux, macOS.
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: interfață Sciter învechită (depreciată)
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: servicii audio/clipboard/input/video și conexiuni de rețea
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: inițiază o conexiune peer
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: comunică cu [rustdesk-server](https://github.com/rustdesk/rustdesk-server), așteaptă conexiune directă remote (TCP hole punching) sau prin relay
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: cod specific platformei
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: cod Flutter pentru desktop și mobil
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/v1/js)**: JavaScript pentru clientul Flutter web
## Capturi de ecran
![Connection Manager](https://github.com/rustdesk/rustdesk/assets/28412477/db82d4e7-c4bc-4823-8e6f-6af7eadf7651)
![Connected to a Windows PC](https://github.com/rustdesk/rustdesk/assets/28412477/9baa91e9-3362-4d06-aa1a-7518edcbd7ea)
![File Transfer](https://github.com/rustdesk/rustdesk/assets/28412477/39511ad3-aa9a-4f8c-8947-1cce286a46ad)
![TCP Tunneling](https://github.com/rustdesk/rustdesk/assets/28412477/78e8708f-e87e-4570-8373-1360033ea6c5)

View File

@@ -1,42 +1,52 @@
<p align="center">
<img src="../res/logo-header.svg" alt="RustDesk - Ваш удаленый рабочий стол"><br>
<a href="#free-public-servers">Servers</a> •
<a href="#raw-steps-to-build">Build</a> •
<a href="#how-to-build-with-docker">Docker</a> •
<a href="#file-structure">Structure</a> •
<a href="#snapshot">Snapshot</a><br>
<a href="#первичные-шаги-для-сборки">Первичные шаги для сборки</a> •
<a href="#как-собрать-с-помощью-Docker">Как собрать с помощью Docker</a> •
<a href="#структура-файлов">Структура файлов</a> •
<a href="#скриншоты">Скриншоты</a><br>
[<a href="../README.md">English</a>] | [<a href="README-UA.md">Українська</a>] | [<a href="README-CS.md">česky</a>] | [<a href="README-ZH.md">中文</a>] | [<a href="README-HU.md">Magyar</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FA.md">فارسی</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-ID.md">Indonesian</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>] | [<a href="README-KR.md">한국어</a>] | [<a href="README-AR.md">العربي</a>] | [<a href="README-VN.md">Tiếng Việt</a>] | [<a href="README-GR.md">Ελληνικά</a>]<br>
<b>Нам нужна ваша помощь для перевода этого README <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a>
и документацию RustDesk на ваш родной язык. <a href="https://github.com/rustdesk/doc.rustdesk.com">RustDesk Doc</a></b>
<b>Нам нужна ваша помощь в переводе этого README, <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">интерфейса RustDesk</a>
и <a href="https://github.com/rustdesk/doc.rustdesk.com">документации RustDesk</a> на ваш родной язык.</b>
</p>
Общение с нами: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
> [!Caution]
> **Отказ от ответственности за неправомерное использование** <br>
> Разработчики RustDesk не одобряют и не поддерживают какое-либо неэтичное или незаконное использование данного программного обеспечения. Неправомерное использование (несанкционированный доступ, контроль или вторжение в частную жизнь) строго противоречит нашим правилам. Авторы не несут ответственности за любое неправомерное использование приложения.
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
Общение с нами: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
Еще одно программное обеспечение для удаленного рабочего стола, написанное на Rust. Работает из коробки, не требует настройки. Вы полностью контролируете свои данные, не беспокоясь о безопасности. Вы можете использовать наш сервер ретрансляции, [настроить свой собственный](https://rustdesk.com/server), или [написать свой](https://github.com/rustdesk/rustdesk-server-demo).
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-%D0%A0%D0%B0%D1%81%D1%88%D0%B8%D1%80%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5%20%D0%92%D0%BE%D0%B7%D0%BC%D0%BE%D0%B6%D0%BD%D0%BE%D1%81%D1%82%D0%B8-blue)](https://rustdesk.com/pricing.html)
Ещё одно программное обеспечение для удаленного рабочего стола, написанное на Rust. Работает из коробки, настройки не требует. Вы полностью контролируете свои данные, не беспокоясь о безопасности. Вы можете использовать наш сервер ретрансляции, [настроить свой собственный](https://rustdesk.com/server), или [написать свой](https://github.com/rustdesk/rustdesk-server-demo).
![image](https://user-images.githubusercontent.com/71636191/171661982-430285f0-2e12-4b1d-9957-4a58e375304d.png)
RustDesk приветствует вклад каждого. Ознакомьтесь с [`docs/CONTRIBUTING-RU.md`](CONTRIBUTING-RU.md) в начале работы для понимания.
[**Как работает RustDesk?**](https://github.com/rustdesk/rustdesk/wiki/How-does-RustDesk-work%3F)
[**Как работает RustDesk?**](https://github.com/rustdesk/rustdesk/wiki/How-does-RustDesk-work%3F) (Документация на английском языке)
[**Часто задаваемые вопросы**](https://github.com/rustdesk/rustdesk/wiki/FAQ) (Страница на английском языке)
[**СКАЧАТЬ ПРИЛОЖЕНИЕ**](https://github.com/rustdesk/rustdesk/releases)
[**ночные сборки (актуальные)**](https://github.com/rustdesk/rustdesk/releases/tag/nightly)
[**НОЧНЫЕ СБОРКИ (Актуальные)**](https://github.com/rustdesk/rustdesk/releases/tag/nightly)
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" alt="Get it on F-Droid" height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
[<img src="https://f-droid.org/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
[<img src="https://flathub.org/api/badge?svg&locale=en"
alt="Get it on Flathub"
height="80">](https://flathub.org/apps/com.rustdesk.RustDesk)
## Зависимости
Настольные версии используют [sciter](https://sciter.com/) для графического интерфейса, загрузите динамическую библиотеку sciter самостоятельно.
Для ПК-версии используются библиотеки Flutter или Sciter (устаревшее) для графического интерфейса. Данное руководство подразумевает работу с Sciter, так как он более простой в использовании и с ним легче начать работу. Вы можете также посмотреть на механизм нашего [CI](https://github.com/rustdesk/rustdesk/blob/master/.github/workflows/flutter-build.yml) для сборок на Flutter.
Загрузите динамическую библиотеку Flutter самостоятельно.
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
[MacOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
Мобильные версии используют Flutter. В будущем мы перенесем настольную версию со Sciter на Flutter.
[macOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
## Первичные шаги для сборки
@@ -45,22 +55,32 @@ RustDesk приветствует вклад каждого. Ознакомьт
- Установите [vcpkg](https://github.com/microsoft/vcpkg), и правильно установите переменную `VCPKG_ROOT`
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static aom:x64-windows-static
- Linux/MacOS: vcpkg install libvpx libyuv opus aom
- Linux/macOS: vcpkg install libvpx libyuv opus aom
- Запустите `cargo run`
- Выполните команду `cargo run`
## [Сборка](https://rustdesk.com/docs/ru/dev/build/)
## Как собрать на Linux
### Ubuntu 18 (Debian 10)
```sh
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev \
libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake make \
libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libpam0g-dev
```
### openSUSE Tumbleweed
```sh
sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel pam-devel
```
### Fedora 28 (CentOS 8)
```sh
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel pam-devel
```
### Arch (Manjaro)
@@ -99,7 +119,7 @@ cd
```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
git clone https://github.com/rustdesk/rustdesk
git clone --recurse-submodules https://github.com/rustdesk/rustdesk
cd rustdesk
mkdir -p target/debug
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
@@ -114,16 +134,17 @@ VCPKG_ROOT=$HOME/vcpkg cargo run
```sh
git clone https://github.com/rustdesk/rustdesk
cd rustdesk
git submodule update --init --recursive
docker build -t "rustdesk-builder" .
```
Затем каждый раз, когда вам нужно собрать приложение, запускайте следующую команду:
Затем при каждой сборке приложения выполняйте следующую команду:
```sh
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
```
Обратите внимание, что первая сборка может занять больше времени, прежде чем зависимости будут кэшированы, но последующие сборки будут выполняться быстрее. Кроме того, если вам нужно указать другие аргументы для команды сборки, вы можете сделать это в конце команды в переменной `<OPTIONAL-ARGS>`. Например, если вы хотите создать оптимизированную версию, вы должны запустить приведенную выше команду и в конце строки добавить `--release`. Полученный исполняемый файл будет доступен в целевой папке вашей системы и может быть запущен с помощью:
Обратите внимание, что первая сборка может занять больше времени, прежде чем зависимости будут кэшированы, но последующие сборки будут выполняться быстрее. Кроме того, если вам нужно указать другие аргументы для команды сборки, вы можете сделать это в конце команды в переменной `<OPTIONAL-ARGS>`. Например, если вы хотите создать оптимизированную версию, вы должны выполнить приведенную выше команду и в конце строки добавить `--release`. Полученный исполняемый файл будет доступен в целевой папке вашей системы и может быть запущен с помощью следующей команды:
```sh
target/debug/rustdesk
@@ -135,25 +156,28 @@ target/debug/rustdesk
target/release/rustdesk
```
Пожалуйста, убедитесь, что вы запускаете эти команды из корня репозитория RustDesk, иначе приложение не сможет найти необходимые ресурсы. Также обратите внимание, что другие cargo подкоманды, такие как `install` или `run`, в настоящее время не поддерживаются этим методом, поскольку они будут устанавливать или запускать программу внутри контейнера, а не на хосте.
Пожалуйста, убедитесь, что вы запускаете эти команды из корня репозитория RustDesk, иначе приложение не сможет найти необходимые ресурсы. Также обратите внимание, что другие подкоманды Cargo, такие как `install` или `run`, в настоящее время не поддерживаются этим методом, поскольку они будут устанавливать или запускать программу внутри контейнера, а не на хосте.
## Структура файлов
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: видеокодек, конфиг, обертка tcp/udp, protobuf, функции fs для передачи файлов и некоторые другие служебные функции
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: видеокодек, конфигурация, враппер TCP/UDP, protobuf, функции файловой системы для передачи файлов и некоторые другие служебные функции
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: захват экрана
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: специфичное для платформы управление клавиатурой/мышью
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: графический пользовательский интерфейс
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: сервисы аудио/буфера обмена/ввода/видео и сетевых подключений
- **[libs/clipboard](https://github.com/rustdesk/rustdesk/tree/master/libs/clipboard)**: функционал буфера обмена файлами для Windows, Linux, и macOS
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: графический пользовательский интерфейс на Sciter (устаревшее)
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: сервисы аудио, буфера обмена, ввода, видео и сетевых подключений
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: одноранговое соединение
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: свяжитесь с [rustdesk-server](https://github.com/rustdesk/rustdesk-server), дождитесь удаленного прямого (обход TCP NAT) или ретранслируемого соединения
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: связь с [сервером RustDesk](https://github.com/rustdesk/rustdesk-server), ожидает удаленного прямого (через TCP hole punching) или ретранслируемого соединения
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: специфичный для платформы код
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: код Flutter для ПК-версии и мобильных устройств
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/v1/js)**: JavaScript для Web-клиента Flutter
## Скриншоты
![image](https://user-images.githubusercontent.com/71636191/113112362-ae4deb80-923b-11eb-957d-ff88daad4f06.png)
![Менеджер соединений](https://github.com/rustdesk/rustdesk/assets/28412477/db82d4e7-c4bc-4823-8e6f-6af7eadf7651)
![image](https://user-images.githubusercontent.com/71636191/113112619-f705a480-923b-11eb-911d-97e984ef52b6.png)
![Подключение к удалённому рабочему столу на Windows](https://github.com/rustdesk/rustdesk/assets/28412477/9baa91e9-3362-4d06-aa1a-7518edcbd7ea)
![image](https://user-images.githubusercontent.com/71636191/113112857-3fbd5d80-923c-11eb-9836-768325faf906.png)
![Передача файлов](https://github.com/rustdesk/rustdesk/assets/28412477/39511ad3-aa9a-4f8c-8947-1cce286a46ad)
![image](https://user-images.githubusercontent.com/71636191/135385039-38fdbd72-379a-422d-b97f-33df71fb1cec.png)
![TCP-туннелирование](https://github.com/rustdesk/rustdesk/assets/28412477/78e8708f-e87e-4570-8373-1360033ea6c5)

View File

@@ -7,34 +7,37 @@
<a href="#file-structure">Dosya Yapısı</a> •
<a href="#snapshot">Ekran Görüntüleri</a><br>
[<a href="docs/README-UA.md">Українська</a>] | [<a href="docs/README-CS.md">česky</a>] | [<a href="docs/README-ZH.md">中文</a>] | [<a href="docs/README-HU.md">Magyar</a>] | [<a href="docs/README-ES.md">Español</a>] | [<a href="docs/README-FA.md">فارسی</a>] | [<a href="docs/README-FR.md">Français</a>] | [<a href="docs/README-DE.md">Deutsch</a>] | [<a href="docs/README-PL.md">Polski</a>] | [<a href="docs/README-ID.md">Indonesian</a>] | [<a href="docs/README-FI.md">Suomi</a>] | [<a href="docs/README-ML.md">മലയാളം</a>] | [<a href="docs/README-JP.md">日本語</a>] | [<a href="docs/README-NL.md">Nederlands</a>] | [<a href="docs/README-IT.md">Italiano</a>] | [<a href="docs/README-RU.md">Русский</a>] | [<a href="docs/README-PTBR.md">Português (Brasil)</a>] | [<a href="docs/README-EO.md">Esperanto</a>] | [<a href="docs/README-KR.md">한국어</a>] | [<a href="docs/README-AR.md">العربي</a>] | [<a href="docs/README-VN.md">Tiếng Việt</a>] | [<a href="docs/README-DA.md">Dansk</a>] | [<a href="docs/README-GR.md">Ελληνικά</a>]<br>
<b>README, <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> ve <a href="https://github.com/rustdesk/doc.rustdesk.com">RustDesk Belge</a>'sini ana dilinize çevirmemiz için yardımınıza ihtiyacımız var</b>
<b>README, <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> ve <a href="https://github.com/rustdesk/doc.rustdesk.com">RustDesk Dökümantasyonu</a>'nu ana dilinize çevirmemiz için yardımınıza ihtiyacımız var</b>
</p>
Bizimle sohbet edin: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
> [!Dikkat]
> **Yanlış Kullanım Uyarısı:** <br>
> RustDesk geliştiricileri, bu yazılımın etik olmayan veya yasa dışı kullanımını onaylamaz veya desteklemez. Yetkisiz erişim, kontrol veya gizlilik ihlali gibi kötüye kullanımlar kesinlikle yönergelerimize aykırıdır. Yazarlar, uygulamanın herhangi bir yanlış kullanımından sorumlu değildir.
Başka bir uzak masaüstü yazılımı daha, Rust dilinde yazılmış. Hemen kullanıma hazır, hiçbir yapılandırma gerektirmez. Verilerinizin tam kontrolünü elinizde tutarsınız ve güvenlikle ilgili endişeleriniz olmaz. Kendi buluş/iletme sunucumuzu kullanabilirsiniz, [kendi sunucunuzu kurabilirsiniz](https://rustdesk.com/server) veya [kendi buluş/iletme sunucunuzu yazabilirsiniz](https://github.com/rustdesk/rustdesk-server-demo).
Bizimle sohbet edin: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-Geli%C5%9Fmi%C5%9F%20%C3%96zellikler-blue)](https://rustdesk.com/pricing.html)
Rust dilinde yazılmış, başka bir uzak masaüstü yazılımı daha. Hiçbir yapılandırma gerekmeksizin, hemen kullanıma hazır. Güvenlik konusunda hiçbir endişe duymadan, verileriniz üzerinde tam kontrole sahip olun. Kendi rendezvous/relay sunucumuzu kullanabilirsiniz, [kendi sunucunuzu kurabilirsiniz](https://rustdesk.com/server) veya [kendi rendezvous/relay sunucunuzu yazabilirsiniz](https://github.com/rustdesk/rustdesk-server-demo).
![image](https://user-images.githubusercontent.com/71636191/171661982-430285f0-2e12-4b1d-9957-4a58e375304d.png)
RustDesk, herkesten katkıyı kabul eder. Başlamak için [CONTRIBUTING.md](docs/CONTRIBUTING-TR.md) belgesine göz atın.
RustDesk, herkesin katkısına açıktır. Başlamak için [CONTRIBUTING.md](CONTRIBUTING-TR.md) belgesine göz atın.
[**SSS**](https://github.com/rustdesk/rustdesk/wiki/FAQ)
[**BİNARİ İNDİR**](https://github.com/rustdesk/rustdesk/releases)
[**BINARY İNDİR**](https://github.com/rustdesk/rustdesk/releases)
[**NİGHTLY DERLEME**](https://github.com/rustdesk/rustdesk/releases/tag/nightly)
[**NIGHTLY DERLEME**](https://github.com/rustdesk/rustdesk/releases/tag/nightly)
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
alt="F-Droid'de Alın"
height="80">](https://f-droid.org/en/packages/com.carriez.flutter_hbb)
## Bağımlılıklar
## Gereksinimler
Masaüstü sürümleri GUI için
[Sciter](https://sciter.com/) veya Flutter kullanır, bu kılavuz sadece Sciter içindir.
Masaüstü sürümleri GUI için; [Sciter](https://sciter.com/)(kaldırılacak) veya Flutter kullanır. Sciter daha kolay ve başlamak için daha dostcanlısı, bundan dolayı bu kılavuz sadece Sciter içindir. Flutter sürümünü derlemek için [CI](https://github.com/rustdesk/rustdesk/blob/master/.github/workflows/flutter-build.yml)'ımıza bakın.
Lütfen Sciter dinamik kütüphanesini kendiniz indirin.
@@ -46,7 +49,7 @@ Lütfen Sciter dinamik kütüphanesini kendiniz indirin.
- Rust geliştirme ortamınızı ve C++ derleme ortamınızı hazırlayın.
- [vcpkg](https://github.com/microsoft/vcpkg) yükleyin ve `VCPKG_ROOT` çevresel değişkenini doğru bir şekilde ayarlayın.
- [vcpkg](https://github.com/microsoft/vcpkg) yükleyin ve `VCPKG_ROOT` ortam değişkenini doğru bir şekilde ayarlayın.
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static aom:x64-windows-static
- Linux/macOS: vcpkg install libvpx libyuv opus aom
@@ -123,7 +126,7 @@ VCPKG_ROOT=$HOME/vcpkg cargo run
## Docker ile Derleme Nasıl Yapılır
Öncelikle deposunu klonlayın ve Docker konteynerini oluşturun:
Önce repository'i klonlayın ve Docker container'ını oluşturun.
```sh
git clone https://github.com/rustdesk/rustdesk
@@ -131,40 +134,40 @@ cd rustdesk
docker build -t "rustdesk-builder" .
```
Ardından, uygulamayı derlemek için her seferinde aşağıdaki komutu çalıştırın:
Ardından, uygulamayı her derlemeniz gerektiğinde aşağıdaki komutu çalıştırın:
```sh
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
```
İlk derleme, bağımlılıklar önbelleğe alınmadan önce daha uzun sürebilir, sonraki derlemeler daha hızlı olacaktır. Ayrıca, derleme komutuna isteğe bağlı argümanlar belirtmeniz gerekiyorsa, bunu
komutun sonunda `<İSTEĞE BAĞLI-ARGÜMANLAR>` pozisyonunda yapabilirsiniz. Örneğin, optimize edilmiş bir sürümü derlemek isterseniz, yukarıdaki komutu çalıştırdıktan sonra `--release` ekleyebilirsiniz. Oluşan yürütülebilir dosya sisteminizdeki hedef klasöründe bulunacak ve şu komutla çalıştırılabilir:
Bilin ki ilk derlemeniz gereksinimlerin önbelleği yüklenmesinden ötürü uzun sürebilir, sonraki derlemeleriniz daha hızlı olacaktır. Ayrıca, derleme komutuna isteğe bağlı argümanlar belirtmeniz gerekiyorsa, bunu komutun sonunda ki `<OPTIONAL-ARGS>` yerine yazabilirsiniz. Örneğin, optimize edilmiş bir sürümü derlemek isterseniz, yukarıdaki komutu çalıştırdıktan sonra `--release` ekleyebilirsiniz. Oluşan çalıştırılabilir dosya sisteminizdeki hedef klasöründe bulunacak ve şu komutla çalıştırılabilir olacaktır:
```sh
target/debug/rustdesk
```
Veya, yayın yürütülebilir dosyası çalıştırılıyorsa:
Veya, yayım çalıştırılabilir dosyası için:
```sh
target/release/rustdesk
```
Lütfen bu komutları RustDesk deposunun kökünden çalıştırdığınızdan emin olun, aksi takdirde uygulama gereken kaynakları bulamayabilir. Ayrıca, `install` veya `run` gibi diğer cargo altkomutları şu anda bu yöntem aracılığıyla desteklenmemektedir, çünkü bunlar programı konteyner içinde kurar veya çalıştırır ve ana makinede değil.
Lütfen bu komutları RustDesk reposunun root klasöründe çalıştırdığınızdan emin olun, aksi takdirde uygulama gereken kaynakları bulamayabilir. Ayrıca, `install` veya `run` gibi diğer cargo altkomutları şu anda bu yöntem aracılığıyla desteklenmemektedir, çünkü bunlar programı konteyner içinde kurar veya çalıştırır, ana makinede değil.
## Dosya Yapısı
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video kodlayıcı, yapılandırma, tcp/udp sarmalayıcı, protobuf, dosya transferi için fs işlevleri ve diğer bazı yardımcı işlevler
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video codec, config, tcp/udp wrapper, protobuf, dosya transferi için fs fonksiyonları ve diğer bazı yardımcı işlevler
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: ekran yakalama
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: platforma özgü klavye/fare kontrolü
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: GUI
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: ses/pasta/klavye/video hizmetleri ve ağ bağlantıları
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: bir eş bağlantısı başlatır
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: [rustdesk-server](https://github.com/rustdesk/rustdesk-server) ile iletişim kurar, uzak doğrudan (TCP delik vurma) veya iletme bağlantısını bekler
- **[libs/clipboard](https://github.com/rustdesk/rustdesk/tree/master/libs/clipboard)**: platforma özgü kopyala/yapıştır implementasyonları.
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: Eski Sciter UI (kaldırılacak)
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: ses/pano/input/video servisleri ve ağ bağlantıları
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: Eşli bağlantı başlat
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: [rustdesk-server](https://github.com/rustdesk/rustdesk-server) ile iletişime gir, remote direct(TCP delik açma) yada relay bağlantısı için bekle
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: platforma özgü kod
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: mobil için Flutter kodu
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: Flutter web istemcisi için JavaScript
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: Masaüstü ve mobil için Flutter kodu
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/v1/js)**: Flutter web istemcisi için JavaScript
## Ekran Görüntüleri

View File

@@ -9,15 +9,15 @@
<b>Нам потрібна ваша допомога для перекладу цього README, <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">інтерфейсу</a> та <a href="https://github.com/rustdesk/doc.rustdesk.com">документації</a> RustDesk вашою рідною мовою</B>
</p>
Спілкування з нами: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
Спілкування з нами: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-%D0%A0%D0%BE%D0%B7%D1%88%D0%B8%D1%80%D0%B5%D0%BD%D1%96%20%D0%A4%D1%83%D0%BD%D0%BA%D1%86%D1%96%D1%97-blue)](https://rustdesk.com/pricing.html)
Ще один застосунок для віддаленого керування стільницею, написаний на Rust. Працює з коробки, не потребує налаштування. Ви повністю контролюєте свої дані, не турбуючись про безпеку. Ви можете використовувати наш сервер ретрансляції, [налаштувати свій власний](https://rustdesk.com/server), або [написати свій власний сервер ретрансляції](https://github.com/rustdesk/rustdesk-server-demo).
![image](https://user-images.githubusercontent.com/71636191/171661982-430285f0-2e12-4b1d-9957-4a58e375304d.png)
RustDesk вітає внесок кожного. Ознайомтеся з [CONTRIBUTING.md](docs/CONTRIBUTING.md), щоб отримати допомогу на початковому етапі.
RustDesk вітає внесок кожного. Ознайомтеся з [CONTRIBUTING.md](CONTRIBUTING.md), щоб отримати допомогу на початковому етапі.
[**ЧаПи**](https://github.com/rustdesk/rustdesk/wiki/FAQ)
@@ -172,6 +172,3 @@ target/release/rustdesk
![Тунелювання TCP](https://github.com/rustdesk/rustdesk/assets/28412477/78e8708f-e87e-4570-8373-1360033ea6c5)
## [Публічні сервери](#публічні-сервери)
RustDesk підтримується безкоштовним європейським сервером, любʼязно наданим [Codext GmbH](https://codext.link/rustdesk?utm_source=github)

View File

@@ -11,9 +11,9 @@
<b>Chúng tôi rất hoan nghênh sự hỗ trợ của bạn trong việc dịch trang README, trang giao diện người dùng của RustDesk - <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> và trang tài liệu của RustDesk - <a href="https://github.com/rustdesk/doc.rustdesk.com">RustDesk Doc</a> sang Tiếng Việt</b>
</p>
Hãy trao đổi với chúng tôi qua: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
Hãy trao đổi với chúng tôi qua: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-T%C3%ADnh%20N%C4%83ng%20N%C3%A2ng%20Cao-blue)](https://rustdesk.com/pricing.html)
RustDesk là một phần mềm điểu khiển máy tính từ xa mã nguồn mở, được viết bằng Rust. Nó hoạt động ngay sau khi cài đặt, không yêu cầu cấu hình phức tạp. Bạn có toàn quyền kiểm soát với dữ liệu của mình mà không cần phải lo lắng về vấn đề bảo mật. Bạn có thể sử dụng máy chủ rendezvous/relay của chúng tôi hoặc [tự cài đặt máy chủ của riêng mình](https://rustdesk.com/server) hay thậm chí [tự tạo máy chủ rendezvous/relay cho riêng bạn](https://github.com/rustdesk/rustdesk-server-demo).

View File

@@ -8,9 +8,13 @@
[<a href="../README.md">English</a>] | [<a href="README-UA.md">Українська</a>] | [<a href="README-CS.md">česky</a>] | [<a href="README-HU.md">Magyar</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FA.md">فارسی</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-ID.md">Indonesian</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>] | [<a href="README-KR.md">한국어</a>] | [<a href="README-AR.md">العربي</a>] | [<a href="README-VN.md">Tiếng Việt</a>] | [<a href="README-GR.md">Ελληνικά</a>]<br>
</p>
与我们交流: [知乎](https://www.zhihu.com/people/rustdesk) | [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.reddit.com/r/rustdesk)
> [!CAUTION]
> **免责声明:** <br>
> RustDesk 的开发人员不纵容或支持任何不道德或非法的软件使用行为。滥用行为,例如未经授权的访问、控制或侵犯隐私,严格违反我们的准则。作者对应用程序的任何滥用行为概不负责。
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
与我们交流: [知乎](https://www.zhihu.com/people/rustdesk) | [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.reddit.com/r/rustdesk) | [YouTube](https://www.youtube.com/@rustdesk)
[![RustDesk Server Pro](https://img.shields.io/badge/RustDesk%20Server%20Pro-%E9%AB%98%E7%BA%A7%E5%8A%9F%E8%83%BD-blue)](https://rustdesk.com/pricing.html)
远程桌面软件,开箱即用,无需任何配置。您完全掌控数据,不用担心安全问题。您可以使用我们的注册/中继服务器,
或者[自己设置](https://rustdesk.com/server)

16
docs/SECURITY-FR.md Normal file
View File

@@ -0,0 +1,16 @@
# Politique de sécurité
## Signaler une vulnérabilité
Nous accordons une très grande importance à la sécurité du projet. Nous
encourageons tous les utilisateurs à nous signaler toute vulnérabilité qu'ils
découvrent.
Si vous trouvez une vulnérabilité de sécurité dans le projet RustDesk, veuillez
la signaler de manière responsable en envoyant un e-mail à info@rustdesk.com.
À ce stade, nous n'avons pas de programme de bug bounty. Nous sommes une petite
équipe qui s'attaque à un grand défi. Nous vous encourageons vivement à signaler
toute vulnérabilité de manière responsable afin que nous puissions continuer à
développer une application sécurisée pour l'ensemble de la communauté.

7
docs/SECURITY-KR.md Normal file
View File

@@ -0,0 +1,7 @@
# 보안 정책
## 취약점 보고
저희는 프로젝트의 보안을 매우 중요하게 생각합니다. 모든 사용자가 발견한 취약점을 저희에게 보고할 것을 권장합니다. RustDesk 프로젝트에서 보안 취약점이 발견되면 info@rustdesk.com으로 이메일을 보내 책임감 있게 보고해 주시기 바랍니다.
현재로서는 버그 현상금 프로그램이 없습니다. 저희는 큰 문제를 해결하기 위해 노력하는 소규모 팀입니다. 전체 커뮤니티를 위한 안전한 응용 프로그램을 계속 구축할 수 있도록 취약점을 책임감 있게 신고해 주시기 바랍니다.

9
docs/SECURITY-NO.md Normal file
View File

@@ -0,0 +1,9 @@
# Sikkerhets Rettningslinjer
## Reportering av en Sårbarhet
Vi verdsetter pris på sikkerhet for prosjektet høyt. Og oppmunterer alle brukere til å rapportere sårbarheter de oppdager til oss.
Om du finner en sikkerhets sårbarhet i RustDesk prosjektet, venligst raportere det ansvarsfult ved å sende oss en email til info@rustdesk.com.
På dette tidspunktet har vi ingen bug dusør program. Vi er ett lite team som prøver å løse ett stort problem. Vi trenger att du raporterer alle sårbarhetene
annsvarfult så vi kan fortsettte å bygge ett en sikker applikasjon for hele felleskapet.

9
docs/SECURITY-RO.md Normal file
View File

@@ -0,0 +1,9 @@
# Politica de Securitate
## Raportarea unei Vulnerabilități
Acordăm o mare importanță securității proiectului. Încurajăm toți utilizatorii să ne raporteze orice vulnerabilități pe care le descoperă.
Dacă găsești o vulnerabilitate de securitate în proiectul RustDesk, te rugăm să o raportezi responsabil trimițând un e-mail la info@rustdesk.com.
În acest moment, nu avem un program de recompense pentru descoperirea de bug-uri. Suntem o echipă mică care încearcă să rezolve o problemă mare.
Te rugăm să raportezi orice vulnerabilitate în mod responsabil, astfel încât să putem continua să construim o aplicație sigură pentru întreaga comunitate.

View File

@@ -33,4 +33,4 @@ if [ -z $release ]; then
fi
set -f
#shellcheck disable=2086
VCPKG_ROOT=/vcpkg cargo build $argv
VCPKG_ROOT=/vcpkg cargo build --locked $argv

View File

@@ -1,28 +0,0 @@
[package]
name = "custom_plugin"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "custom_plugin"
path = "src/lib.rs"
crate-type = ["cdylib"]
[features]
default = ["flutter"]
flutter = []
[dependencies]
lazy_static = "1.4.0"
rustdesk = { path = "../../", version = "1.2.0", features = ["flutter"]}
[profile.release]
lto = true
codegen-units = 1
panic = 'abort'
strip = true
#opt-level = 'z' # only have smaller size after strip
rpath = true

View File

@@ -1,30 +0,0 @@
use librustdesk::api::RustDeskApiTable;
/// This file demonstrates how to write a custom plugin for RustDesk.
use std::ffi::{c_char, c_int, CString};
lazy_static::lazy_static! {
pub static ref PLUGIN_NAME: CString = CString::new("A Template Rust Plugin").unwrap();
pub static ref PLUGIN_ID: CString = CString::new("TemplatePlugin").unwrap();
// Do your own logic based on the API provided by RustDesk.
pub static ref API: RustDeskApiTable = RustDeskApiTable::default();
}
#[no_mangle]
fn plugin_name() -> *const c_char {
return PLUGIN_NAME.as_ptr();
}
#[no_mangle]
fn plugin_id() -> *const c_char {
return PLUGIN_ID.as_ptr();
}
#[no_mangle]
fn plugin_init() -> c_int {
return 0 as _;
}
#[no_mangle]
fn plugin_dispose() -> c_int {
return 0 as _;
}

90
examples/ipc.rs Normal file
View File

@@ -0,0 +1,90 @@
use docopt::Docopt;
use hbb_common::{
env_logger::{init_from_env, Env, DEFAULT_FILTER_ENV},
log, tokio,
};
use librustdesk::{ipc::Data, *};
const USAGE: &'static str = "
IPC test program.
Usage:
ipc (-s | --server | -c | --client) [-p <str> | --postfix=<str>]
ipc (-h | --help)
Options:
-h --help Show this screen.
-s --server Run as IPC server.
-c --client Run as IPC client.
-p --postfix=<str> IPC path postfix [default: ].
";
#[derive(Debug, serde::Deserialize)]
struct Args {
flag_server: bool,
flag_client: bool,
flag_postfix: String,
}
#[tokio::main]
async fn main() {
init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info"));
let args: Args = Docopt::new(USAGE)
.and_then(|d| d.deserialize())
.unwrap_or_else(|e| e.exit());
if args.flag_server {
if args.flag_postfix.is_empty() {
log::info!("Starting IPC server...");
} else {
log::info!(
"Starting IPC server with postfix: '{}'...",
args.flag_postfix
);
}
ipc_server(&args.flag_postfix).await;
} else if args.flag_client {
if args.flag_postfix.is_empty() {
log::info!("Starting IPC client...");
} else {
log::info!(
"Starting IPC client with postfix: '{}'...",
args.flag_postfix
);
}
ipc_client(&args.flag_postfix).await;
}
}
async fn ipc_server(postfix: &str) {
let postfix = postfix.to_string();
let postfix2 = postfix.clone();
std::thread::spawn(move || {
if let Err(err) = crate::ipc::start(&postfix) {
log::error!("Failed to start ipc: {}", err);
std::process::exit(-1);
}
});
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
ipc_client(&postfix2).await;
}
async fn ipc_client(postfix: &str) {
loop {
match crate::ipc::connect(1000, postfix).await {
Ok(mut conn) => match conn.send(&Data::Empty).await {
Ok(_) => {
log::info!("send message to ipc server success");
}
Err(e) => {
log::error!("Failed to send message to ipc server: {}", e);
}
},
Err(e) => {
log::error!("Failed to connect to ipc server: {}", e);
}
}
tokio::time::sleep(std::time::Duration::from_secs(6)).await;
}
}

View File

@@ -1 +1 @@
An open-source remote desktop application, the open source TeamViewer alternative.
An open-source remote desktop application, the TeamViewer alternative

View File

@@ -18,7 +18,7 @@
<li> Supports VP8 / VP9 / AV1 software codecs, and H264 / H265 hardware codecs. </li>
<li> Own your data, easily set up self-hosting solution on your infrastructure. </li>
<li> P2P connection with end-to-end encryption based on NaCl. </li>
<li> No administrative privileges or installation needed for Windows, elevate priviledge locally or from remote on demand. </li>
<li> No administrative privileges or installation needed for Windows, elevate privilege locally or from remote on demand. </li>
<li> We like to keep things simple and will strive to make simpler where possible. </li>
</ul>
<p>
@@ -56,4 +56,4 @@
<control>pointing</control>
</supports>
<content_rating type="oars-1.1"/>
</component>
</component>

View File

@@ -55,8 +55,8 @@
],
"finish-args": [
"--share=ipc",
"--socket=fallback-x11",
"--socket=wayland",
"--socket=x11",
"--share=network",
"--filesystem=home",
"--device=dri",

View File

@@ -1,4 +1,6 @@
import com.google.protobuf.gradle.*
import groovy.json.JsonSlurper
plugins {
id "com.google.protobuf" version "0.9.4"
id "com.android.application"
@@ -30,8 +32,37 @@ if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
dependencies {
implementation 'com.google.protobuf:protobuf-javalite:3.20.1'
// Add rustls-platform-verifier Android support
String findRustlsPlatformVerifierMavenDir() {
def dependencyText = providers.exec {
it.workingDir = new File("../..")
commandLine("cargo", "metadata", "--format-version", "1")
}.standardOutput.asText.get()
def dependencyJson = new JsonSlurper().parseText(dependencyText)
def pkg = dependencyJson.packages.find { it.name == "rustls-platform-verifier-android" }
if (pkg == null) {
throw new GradleException("rustls-platform-verifier-android package not found in cargo metadata!")
}
def manifestPath = file(pkg.manifest_path)
def mavenDir = new File(manifestPath.parentFile, "maven")
if (!mavenDir.exists()) {
throw new GradleException("Maven directory not found at: ${mavenDir.path}")
}
println("✓ Found rustls-platform-verifier maven repo at: ${mavenDir.path}")
return mavenDir.path
}
repositories {
maven {
url = findRustlsPlatformVerifierMavenDir()
metadataSources.artifact()
}
}
protobuf {
@@ -67,7 +98,7 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.carriez.flutter_hbb"
minSdkVersion 21
minSdkVersion 22
targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
@@ -97,8 +128,10 @@ flutter {
}
dependencies {
implementation 'com.google.protobuf:protobuf-javalite:3.20.1'
implementation "androidx.media:media:1.6.0"
implementation 'com.github.getActivity:XXPermissions:18.5'
implementation("org.jetbrains.kotlin:kotlin-stdlib") { version { strictly("1.9.10") } }
implementation 'com.caverock:androidsvg-aar:1.4'
implementation "rustls:rustls-platform-verifier:0.1.1"
}

View File

@@ -1,4 +1,7 @@
# Keep class members from protobuf generated code.
-keepclassmembers class * extends com.google.protobuf.GeneratedMessageLite {
<fields>;
}
}
# Keep rustls-platform-verifier classes for JNI
-keep, includedescriptorclasses class org.rustls.platformverifier.** { *; }

View File

@@ -23,6 +23,7 @@
</queries>
<application
android:name=".MainApplication"
android:icon="@mipmap/ic_launcher"
android:label="RustDesk"
android:requestLegacyExternalStorage="true"

View File

@@ -62,7 +62,13 @@ class AudioRecordHandle(private var context: Context, private var isVideoStart:
return false
}
}
audioRecorder = builder.build()
val recorder = try {
builder.build()
} catch (e: Exception) {
Log.e(logTag, "createAudioRecorder failed", e)
return false
}
audioRecorder = recorder
Log.d(logTag, "createAudioRecorder done,minBufferSize:$minBufferSize")
return true
}

View File

@@ -311,7 +311,10 @@ class FloatingWindowService : Service(), View.OnTouchListener {
popupMenu.menu.add(0, idSyncClipboard, 0, translate("Update client clipboard"))
}
val idStopService = 2
popupMenu.menu.add(0, idStopService, 0, translate("Stop service"))
val hideStopService = FFI.getBuildinOption("hide-stop-service") == "Y"
if (!hideStopService) {
popupMenu.menu.add(0, idStopService, 0, translate("Stop service"))
}
popupMenu.setOnMenuItemClickListener { menuItem ->
when (menuItem.itemId) {
idShowRustDesk -> {
@@ -389,4 +392,3 @@ class FloatingWindowService : Service(), View.OnTouchListener {
return false
}
}

View File

@@ -8,6 +8,7 @@ package com.carriez.flutter_hbb
import android.accessibilityservice.AccessibilityService
import android.accessibilityservice.GestureDescription
import android.content.Intent
import android.graphics.Path
import android.os.Build
import android.os.Bundle
@@ -19,6 +20,7 @@ import android.view.accessibility.AccessibilityEvent
import android.view.ViewGroup.LayoutParams
import android.view.accessibility.AccessibilityNodeInfo
import android.view.KeyEvent as KeyEventAndroid
import android.view.ViewConfiguration
import android.graphics.Rect
import android.media.AudioManager
import android.accessibilityservice.AccessibilityServiceInfo
@@ -34,10 +36,15 @@ import hbb.MessageOuterClass.KeyEvent
import hbb.MessageOuterClass.KeyboardMode
import hbb.KeyEventConverter
const val LIFT_DOWN = 9
const val LIFT_MOVE = 8
const val LIFT_UP = 10
// const val BUTTON_UP = 2
// const val BUTTON_BACK = 0x08
const val LEFT_DOWN = 9
const val LEFT_MOVE = 8
const val LEFT_UP = 10
const val RIGHT_UP = 18
// (BUTTON_BACK << 3) | BUTTON_UP
const val BACK_UP = 66
const val WHEEL_BUTTON_DOWN = 33
const val WHEEL_BUTTON_UP = 34
const val WHEEL_DOWN = 523331
@@ -62,14 +69,27 @@ class InputService : AccessibilityService() {
get() = ctx != null
}
private fun notifyInputState() {
val inputState = isOpen.toString()
Handler(Looper.getMainLooper()).post {
MainActivity.flutterMethodChannel?.invokeMethod(
"on_state_changed",
mapOf("name" to "input", "value" to inputState)
)
}
}
private val logTag = "input service"
private var leftIsDown = false
private var touchPath = Path()
private var stroke: GestureDescription.StrokeDescription? = null
private var lastTouchGestureStartTime = 0L
private var mouseX = 0
private var mouseY = 0
private var timer = Timer()
private var recentActionTask: TimerTask? = null
// 100(tap timeout) + 400(long press timeout)
private val longPressDuration = ViewConfiguration.getTapTimeout().toLong() + ViewConfiguration.getLongPressTimeout().toLong()
private val wheelActionsQueue = LinkedList<GestureDescription>()
private var isWheelActionsPolling = false
@@ -77,6 +97,9 @@ class InputService : AccessibilityService() {
private var fakeEditTextForTextStateCalculation: EditText? = null
private var lastX = 0
private var lastY = 0
private val volumeController: VolumeController by lazy { VolumeController(applicationContext.getSystemService(AUDIO_SERVICE) as AudioManager) }
@RequiresApi(Build.VERSION_CODES.N)
@@ -84,7 +107,7 @@ class InputService : AccessibilityService() {
val x = max(0, _x)
val y = max(0, _y)
if (mask == 0 || mask == LIFT_MOVE) {
if (mask == 0 || mask == LEFT_MOVE) {
val oldX = mouseX
val oldY = mouseY
mouseX = x * SCREEN_INFO.scale
@@ -98,31 +121,30 @@ class InputService : AccessibilityService() {
}
}
// left button down ,was up
if (mask == LIFT_DOWN) {
// left button down, was up
if (mask == LEFT_DOWN) {
isWaitingLongPress = true
timer.schedule(object : TimerTask() {
override fun run() {
if (isWaitingLongPress) {
isWaitingLongPress = false
leftIsDown = false
endGesture(mouseX, mouseY)
continueGesture(mouseX, mouseY)
}
}
}, LONG_TAP_DELAY * 4)
}, longPressDuration)
leftIsDown = true
startGesture(mouseX, mouseY)
return
}
// left down ,was down
// left down, was down
if (leftIsDown) {
continueGesture(mouseX, mouseY)
}
// left up ,was down
if (mask == LIFT_UP) {
// left up, was down
if (mask == LEFT_UP) {
if (leftIsDown) {
leftIsDown = false
isWaitingLongPress = false
@@ -132,6 +154,11 @@ class InputService : AccessibilityService() {
}
if (mask == RIGHT_UP) {
longPress(mouseX, mouseY)
return
}
if (mask == BACK_UP) {
performGlobalAction(GLOBAL_ACTION_BACK)
return
}
@@ -241,18 +268,100 @@ class InputService : AccessibilityService() {
}
}
private fun startGesture(x: Int, y: Int) {
touchPath = Path()
touchPath.moveTo(x.toFloat(), y.toFloat())
lastTouchGestureStartTime = System.currentTimeMillis()
}
private fun continueGesture(x: Int, y: Int) {
touchPath.lineTo(x.toFloat(), y.toFloat())
@RequiresApi(Build.VERSION_CODES.N)
private fun performClick(x: Int, y: Int, duration: Long) {
val path = Path()
path.moveTo(x.toFloat(), y.toFloat())
try {
val longPressStroke = GestureDescription.StrokeDescription(path, 0, duration)
val builder = GestureDescription.Builder()
builder.addStroke(longPressStroke)
Log.d(logTag, "performClick x:$x y:$y time:$duration")
dispatchGesture(builder.build(), null, null)
} catch (e: Exception) {
Log.e(logTag, "performClick, error:$e")
}
}
@RequiresApi(Build.VERSION_CODES.N)
private fun endGesture(x: Int, y: Int) {
private fun longPress(x: Int, y: Int) {
performClick(x, y, longPressDuration)
}
private fun startGesture(x: Int, y: Int) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
touchPath.reset()
} else {
touchPath = Path()
}
touchPath.moveTo(x.toFloat(), y.toFloat())
lastTouchGestureStartTime = System.currentTimeMillis()
lastX = x
lastY = y
}
@RequiresApi(Build.VERSION_CODES.N)
private fun doDispatchGesture(x: Int, y: Int, willContinue: Boolean) {
touchPath.lineTo(x.toFloat(), y.toFloat())
var duration = System.currentTimeMillis() - lastTouchGestureStartTime
if (duration <= 0) {
duration = 1
}
try {
if (stroke == null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
stroke = GestureDescription.StrokeDescription(
touchPath,
0,
duration,
willContinue
)
} else {
stroke = GestureDescription.StrokeDescription(
touchPath,
0,
duration
)
}
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
stroke = stroke?.continueStroke(touchPath, 0, duration, willContinue)
} else {
stroke = null
stroke = GestureDescription.StrokeDescription(
touchPath,
0,
duration
)
}
}
stroke?.let {
val builder = GestureDescription.Builder()
builder.addStroke(it)
Log.d(logTag, "doDispatchGesture x:$x y:$y time:$duration")
dispatchGesture(builder.build(), null, null)
}
} catch (e: Exception) {
Log.e(logTag, "doDispatchGesture, willContinue:$willContinue, error:$e")
}
}
@RequiresApi(Build.VERSION_CODES.N)
private fun continueGesture(x: Int, y: Int) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
doDispatchGesture(x, y, true)
touchPath.reset()
touchPath.moveTo(x.toFloat(), y.toFloat())
lastTouchGestureStartTime = System.currentTimeMillis()
lastX = x
lastY = y
} else {
touchPath.lineTo(x.toFloat(), y.toFloat())
}
}
@RequiresApi(Build.VERSION_CODES.N)
private fun endGestureBelowO(x: Int, y: Int) {
try {
touchPath.lineTo(x.toFloat(), y.toFloat())
var duration = System.currentTimeMillis() - lastTouchGestureStartTime
@@ -273,6 +382,17 @@ class InputService : AccessibilityService() {
}
}
@RequiresApi(Build.VERSION_CODES.N)
private fun endGesture(x: Int, y: Int) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
doDispatchGesture(x, y, false)
touchPath.reset()
stroke = null
} else {
endGestureBelowO(x, y)
}
}
@RequiresApi(Build.VERSION_CODES.N)
fun onKeyEvent(data: ByteArray) {
val keyEvent = KeyEvent.parseFrom(data)
@@ -607,6 +727,7 @@ class InputService : AccessibilityService() {
override fun onServiceConnected() {
super.onServiceConnected()
ctx = this
notifyInputState()
val info = AccessibilityServiceInfo()
if (Build.VERSION.SDK_INT >= 33) {
info.flags = FLAG_INPUT_METHOD_EDITOR or FLAG_RETRIEVE_INTERACTIVE_WINDOWS
@@ -625,8 +746,16 @@ class InputService : AccessibilityService() {
override fun onDestroy() {
ctx = null
// Keep this fallback even though onUnbind usually notifies first.
notifyInputState()
super.onDestroy()
}
override fun onUnbind(intent: Intent?): Boolean {
ctx = null
notifyInputState()
return super.onUnbind(intent)
}
override fun onInterrupt() {}
}

View File

@@ -62,7 +62,13 @@ class MainActivity : FlutterActivity() {
channelTag
)
initFlutterChannel(flutterMethodChannel!!)
thread { setCodecInfo() }
thread {
try {
setCodecInfo()
} catch (e: Exception) {
Log.e("MainActivity", "Failed to setCodecInfo: ${e.message}", e)
}
}
}
override fun onResume() {
@@ -100,6 +106,16 @@ class MainActivity : FlutterActivity() {
override fun onDestroy() {
Log.e(logTag, "onDestroy")
// The process can outlive the UI whenever something keeps it alive:
// MainService, or the accessibility InputService on its own. Only the
// former gets onTaskRemoved, so close outgoing sessions here too,
// otherwise a session survives with no UI left to close it.
// `isFinishing` distinguishes the user really leaving from a destroy
// for recreation (configuration change, "don't keep activities"),
// which must not tear down a live session.
if (isFinishing) {
FFI.closeAllSessions()
}
mainService?.let {
unbindService(serviceConnection)
}
@@ -194,12 +210,13 @@ class MainActivity : FlutterActivity() {
"stop_input" -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
InputService.ctx?.disableSelf()
} else {
InputService.ctx = null
Companion.flutterMethodChannel?.invokeMethod(
"on_state_changed",
mapOf("name" to "input", "value" to InputService.isOpen.toString())
)
}
InputService.ctx = null
Companion.flutterMethodChannel?.invokeMethod(
"on_state_changed",
mapOf("name" to "input", "value" to InputService.isOpen.toString())
)
result.success(true)
}
"cancel_notification" -> {
@@ -316,7 +333,7 @@ class MainActivity : FlutterActivity() {
codecObject.put("mime_type", mime_type)
val caps = codec.getCapabilitiesForType(mime_type)
if (codec.isEncoder) {
// Encoders max_height and max_width are interchangeable
// Encoder's max_height and max_width are interchangeable
if (!caps.videoCapabilities.isSizeSupported(w,h) && !caps.videoCapabilities.isSizeSupported(h,w)) {
return@forEach
}

View File

@@ -0,0 +1,17 @@
package com.carriez.flutter_hbb
import android.app.Application
import android.util.Log
import ffi.FFI
class MainApplication : Application() {
companion object {
private const val TAG = "MainApplication"
}
override fun onCreate() {
super.onCreate()
Log.d(TAG, "App start")
FFI.onAppStart(applicationContext)
}
}

View File

@@ -65,8 +65,8 @@ class MainService : Service() {
@Keep
@RequiresApi(Build.VERSION_CODES.N)
fun rustPointerInput(kind: Int, mask: Int, x: Int, y: Int) {
// turn on screen with LIFT_DOWN when screen off
if (!powerManager.isInteractive && (kind == 0 || mask == LIFT_DOWN)) {
// turn on screen with LEFT_DOWN when screen off
if (!powerManager.isInteractive && (kind == 0 || mask == LEFT_DOWN)) {
if (wakeLock.isHeld) {
Log.d(logTag, "Turn on Screen, WakeLock release")
wakeLock.release()
@@ -122,9 +122,9 @@ class MainService : Service() {
val authorized = jsonObject["authorized"] as Boolean
val isFileTransfer = jsonObject["is_file_transfer"] as Boolean
val type = if (isFileTransfer) {
translate("File Connection")
translate("Transfer file")
} else {
translate("Screen Connection")
translate("Share screen")
}
if (authorized) {
if (!isFileTransfer && !isStart) {
@@ -254,6 +254,16 @@ class MainService : Service() {
super.onDestroy()
}
// Swiping the app away from recents destroys the UI but this service keeps
// the process alive, so outgoing sessions would stay connected with no way
// to close them. Incoming connections are unaffected: the service keeps
// running so the device stays reachable.
override fun onTaskRemoved(rootIntent: Intent?) {
Log.d(logTag, "onTaskRemoved, closing outgoing sessions")
FFI.closeAllSessions()
super.onTaskRemoved(rootIntent)
}
private var isHalfScale: Boolean? = null;
private fun updateScreenInfo(orientation: Int) {
var w: Int

View File

@@ -13,6 +13,7 @@ object FFI {
}
external fun init(ctx: Context)
external fun onAppStart(ctx: Context)
external fun setClipboardManager(clipboardManager: RdClipboardManager)
external fun startServer(app_dir: String, custom_client_config: String)
external fun startService()
@@ -20,9 +21,11 @@ object FFI {
external fun onAudioFrameUpdate(buf: ByteBuffer)
external fun translateLocale(localeName: String, input: String): String
external fun refreshScreen()
external fun closeAllSessions()
external fun setFrameRawEnable(name: String, value: Boolean)
external fun setCodecInfo(info: String)
external fun getLocalOption(key: String): String
external fun getBuildinOption(key: String): String
external fun onClipboardUpdate(clips: ByteBuffer)
external fun isServiceClipboardEnabled(): Boolean
}

View File

@@ -1,3 +1,4 @@
org.gradle.jvmargs=-Xmx1536M
org.gradle.jvmargs=-Xmx1024M
android.useAndroidX=true
android.enableJetifier=true
org.gradle.daemon=false

View File

@@ -18,8 +18,8 @@ pluginManagement {
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "7.3.0" apply false
id "org.jetbrains.kotlin.android" version "1.9.10" apply false
id "com.android.application" version "7.3.1" apply false
id "org.jetbrains.kotlin.android" version "2.1.21" apply false
}
include ":app"

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

@@ -0,0 +1 @@
<svg width="48" height="48" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg"><rect x="4" y="4" width="19" height="19" fill="#f25022"/><rect x="25" y="4" width="19" height="19" fill="#7fba00"/><rect x="4" y="25" width="19" height="19" fill="#00a4ef"/><rect x="25" y="25" width="19" height="19" fill="#ffb900"/></svg>

After

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

View File

@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<g fill="#000000" fill-rule="evenodd">
<rect x="4" y="6" width="24" height="16" rx="3"/>
<rect x="14.5" y="22" width="3" height="2"/>
<rect x="9.5" y="24" width="13" height="2.5" rx="1.25"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 303 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" style="isolation:isolate" viewBox="541.937 521.772 32 32"><path fill="none" d="M541.937 521.772h32v32h-32v-32Z"/><path fill-rule="evenodd" d="M552.145 539.981h11.584c.446 0 .808.362.808.808v.536c0 .786-.639 1.425-1.425 1.425h-10.35a1.426 1.426 0 0 1-1.425-1.425v-.536c0-.446.362-.808.808-.808Zm-1.761-3.511h.899c.536 0 .971.435.971.971v.899a.971.971 0 0 1-.971.971h-.899a.971.971 0 0 1-.971-.971v-.899c0-.536.435-.971.971-.971Zm3.552 0h.899c.536 0 .971.435.971.971v.899a.971.971 0 0 1-.971.971h-.899a.972.972 0 0 1-.972-.971v-.899c0-.536.436-.971.972-.971Zm3.551 0h.9c.536 0 .971.435.971.971v.899a.971.971 0 0 1-.971.971h-.9a.971.971 0 0 1-.971-.971v-.899c0-.536.435-.971.971-.971Zm3.552 0h.899c.536 0 .972.435.972.971v.899a.972.972 0 0 1-.972.971h-.899a.971.971 0 0 1-.971-.971v-.899c0-.536.435-.971.971-.971Zm3.552 0h.899c.536 0 .971.435.971.971v.899a.971.971 0 0 1-.971.971h-.899a.971.971 0 0 1-.971-.971v-.899c0-.536.435-.971.971-.971Zm-14.383-3.512h1.25c.44 0 .796.357.796.796v1.25a.796.796 0 0 1-.796.796h-1.25a.796.796 0 0 1-.795-.796v-1.25c0-.439.356-.796.795-.796Zm3.552 0h1.25c.439 0 .796.357.796.796v1.25a.797.797 0 0 1-.796.796h-1.25a.797.797 0 0 1-.796-.796v-1.25c0-.439.357-.796.796-.796Zm3.552 0h1.25c.439 0 .796.357.796.796v1.25a.797.797 0 0 1-.796.796h-1.25a.797.797 0 0 1-.796-.796v-1.25c0-.439.357-.796.796-.796Zm3.552 0h1.25c.439 0 .796.357.796.796v1.25a.797.797 0 0 1-.796.796h-1.25a.797.797 0 0 1-.796-.796v-1.25c0-.439.357-.796.796-.796Zm-9.553-3.85h13.252c1.407 0 2.755.507 3.748 1.409.993.902 1.552 2.127 1.552 3.404v7.702c0 1.277-.559 2.501-1.552 3.403-.993.902-2.341 1.409-3.748 1.409h-13.252c-1.407 0-2.755-.507-3.748-1.409-.993-.902-1.552-2.126-1.552-3.403v-7.702c0-1.277.559-2.502 1.552-3.404.993-.902 2.341-1.409 3.748-1.409Zm13.105 3.85h1.25c.439 0 .795.357.795.796v1.25a.796.796 0 0 1-.795.796h-1.25a.796.796 0 0 1-.796-.796v-1.25c0-.439.356-.796.796-.796Z"/></svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.4 KiB

Some files were not shown because too many files have changed in this diff Show More