3145 Commits
Author SHA1 Message Date
rustdesk d5a7f67999 fix appimage pixbuf crash 2026-08-22 12:25:35 +08:00
fufesou 92eb137178 feat(terminal): use platform-native copy and paste shortcuts (#15931) 2026-08-21 21:20:39 +08:00
palmoni5 61ddade049 fix(windows): restore keyboard focus when the cursor re-enters the remote image (#15880)
* fix(windows): restore keyboard focus when the cursor re-enters the remote image

On Windows the raw key focus node is unfocused on window blur and nothing
requests it back, so returning to an already connected session left the
keyboard dead until the remote image was clicked.

Request focus from enterView(), gated on the window being active, the tab
being selected and no blocking overlay, so a background window cannot grab
system keys. enterOrLeave(true) is still driven by RawKeyFocusScope's
onFocusChange, so it is not called twice.

* fix(windows): refocus on window focus when the cursor already hovers the image

Alt+Tab or a taskbar click returns focus without a PointerEnter, so
enterView() cannot restore the keyboard. Reuse _cursorOverImage, gated
on the selected tab and no blocking overlay.

* refactor(windows): share one focus predicate for every requestFocus path

The relative-mouse-mode restore on window focus could hand remote input
to this page while a blocking dialog was up or the tab was not selected.
2026-08-21 17:07:25 +08:00
fufesou c78bdefc44 fix: dialog, trackpad speed, buttons (close -> ok, cancel) (#15918)
* fix: dialog, trackpad speed, buttons (close -> ok, cancel)

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

* fix(flutter): handle trackpad speed dialog submission

- commit typed values from Enter and OK
- validate input before saving
- prevent duplicate submissions
- surface save failures

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

* fix(flutter): sync trackpad speed input and slider

- handle trackpad speed submission from IME actions
- update the slider when a valid speed is typed
- cover Enter, OK, IME, and invalid input behavior

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-08-21 14:15:35 +08:00
fufesou 0a4b431ea2 fix: correct terminal mouse selection and scroll coordinates (#15915)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-08-20 13:10:45 +08:00
21pages 5679670506 fix(flutter): make Adjust Window reliable across desktop platforms (#15853)
* fix(flutter): make Adjust Window reliable across desktop platforms

  - Fix incorrect sizing on scaled displays by calculating the target from the
    rendered canvas scale and platform-specific window coordinate units.
  - Fix adjustments using the wrong monitor by querying the current remote
    window's screen, with the main window as fallback.
  - Fix stale geometry after fullscreen or maximized transitions by refreshing
    metrics before calculating and applying the target frame.
  - Fix fullscreen availability checks on Windows and macOS by predicting the
    restored window borders and caching each macOS window's pre-fullscreen work area.
  - Fix incorrect Linux work areas by handling GNOME Wayland fractional scaling
    and caching compositor/X11 work-area measurements when visibleFrame is wrong.
  - Prevent unsafe adjustments by rejecting invalid, oversized, or implausibly
    small target frames.
  - Avoid failures during window teardown by skipping adjustment when the view,
    screen, or native window frame is unavailable.

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

* fix(flutter): harden Adjust Window handling

  - Use the dynamic Linux resize edge when predicting restored window bounds.
  - Treat GNOME fractional-scaling lookup failures as unknown without repeating
    the lookup for the remote window.
  - Stop adjustment safely when native window calls fail during window teardown.

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

* fix(flutter): correct Linux monitor selection

Update window_size to use monitor height for vertical bounds, preventing incorrect screen selection with vertically stacked displays.

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

* docs(flutter): simplify Linux screen handling comments

Keep the source rationale concise and move platform measurements and investigation details out of the implementation.

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

* fix(flutter): align Adjust Window resize padding

Use the shared drag-to-resize padding for Linux restored-window predictions so menu validation matches the applied frame dimensions.

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

* fix(flutter): remove Adjust Window screen fallback

Return null when the current window screen is unavailable instead of using the main window's scale factor and work area.

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

* fix(linux): query Mutter monitor layout mode

  Use DisplayConfig.GetCurrentState instead of inferring scaling from
  experimental features, and handle Ubuntu's UI-scaled logical mode.

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

* fix(flutter): use native maximized state for Wayland cache

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

* fix(flutter): allow Adjust Window to fill work area

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

* fix(flutter): avoid racing screen info updates

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

* refactor(flutter): remove dead Adjust Window web plumbing

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

* fix(flutter): tolerate near-unity Wayland scale factors

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

* fix(flutter): harden window screen detection

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

* fix(linux): drop deprecated GNOME session detection

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

* fix(flutter): remove GNOME monitor layout mode flutter cache

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

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-08-19 15:08:58 +08:00
Mariano Abad 630b531108 fix(flutter): initialize the cursor hotspot y from its own origin (#15898)
The CursorData constructor copies hotxOrigin into hoty. Latent today:
both consumers call updateGetKey() before reading, and _checkUpdateScale
recomputes hoty from hotyOrigin - but any future read before that call
inherits the x value silently.
2026-08-19 12:49:28 +08:00
RustDeskandClaude Opus 5 1984678785 Hide printer tab when settings disabled (#15901)
* fix: hide the printer settings tab when settings are disabled

The Security and Network tabs already honour `disable-settings`, but the
Printer tab was gated only on `hide-remote-printer-settings`, so custom
clients built with settings disabled still exposed it.

https://github.com/rustdesk/rustdesk-server-pro/issues/1001

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

* feat: add hide-general-settings builtin option

Hides the General tab of the settings page. Unlike the other
hide-*-settings options this one is still useful when settings are
disabled, since `disable-settings` does not cover the General tab.

https://github.com/rustdesk/rustdesk-server-pro/issues/1001

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 10:48:30 +08:00
fufesou b0008edcb5 refact: remove linux headless (#15866)
* refact: remove linux headless

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

* fix(linux): probe DRM availability asynchronously on login

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

* revert changes in drm_capturer.rs

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

* Update submodule hbb_common

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

* docs(linux): clarify DRM availability comments

Remove stale headless and unauthenticated-request
wording, and document the Available-only login-screen gate.

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

* fix(linux): remove unreachable session cleanup branch

Remove the obsolete empty-session path and
clarify the intended use of cached DRM availability.

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-08-18 15:02:50 +08:00
Krik JINgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>Krik Jinfufesou
8ffe3117a5 feat(flutter): add mobile canvas lock (#15877)
* feat: add mobile canvas lock

* Update flutter/lib/models/model.dart

Remove redundant canvas-lock comment

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

* remove redundant logic

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: Krik Jin <isjinhk@outlook.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: fufesou <linlong1266@gmail.com>
2026-08-17 17:04:58 +08:00
7aa98d43cf Refact/plugin removal leftovers (#15864)
* fix(flutter): dispose the settings PageController and order dispose() correctly

`dispose()` began with `super.dispose()`, so the mixin chain marked the State
defunct before the WidgetsBindingObserver registration and the periodic timer
were released. The `PageController` was never disposed at all: `Get.delete`
only runs `onDelete()` for a `GetLifeCycleBase`, and a plain `ChangeNotifier`
is not one, so every open/close of the Settings tab leaked one controller with
its listener still attached.

Also guard `switch2page` on the `Rx<SettingsTabKey>` registration it actually
reads rather than only the `PageController` — now that both are really
deleted, a partial teardown would throw into the catch and silently open the
wrong tab — and re-check `mounted` after the await in the `_videoConnTimer`
tick, which `Timer::cancel` cannot stop once the body has started.

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

* refact: finish the plugin-framework removal sweep

#15854 removed the feature but stopped short of its leftovers:

- `Uninstall`, `Enable`, `Disable`, `Options` and `Please install plugins`
  were consumed only by the deleted `flutter/lib/plugin/**`; drop them from
  template.rs and the 50 locale files (250 dead entries). `Update` and
  `Install` stay, still used by desktop_home_page.dart.
- The server no longer sends `PrvOnFailedPlugin`, and the client no longer
  offers to install plugins when privacy mode fails to turn on.
- Drop the MSI `F_Client_Plugins` / `F_Server_Plugins` localization strings;
  no `.wxs` references them.
- `_DisplayMenu`'s constructor became a pure pass-through once `pluginItem`
  was removed, and the cfg inside `handle_input` repeats the one on the
  function itself.
- Normalize `src/lang/sl.rs` to 0644, the only executable file under src/.

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

* fix(client): handle legacy privacy mode plugin failures

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: fufesou <linlong1266@gmail.com>
2026-08-14 18:52:03 +08:00
fufesou d1da05c4db refact: remove feature plugin-framework (#15854)
* refact: remove feature plugin-framework

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

* refact: remove unused translations

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

* fix: delete settings tab observable with correct type

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-08-14 14:31:13 +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
RustDeskandClaude Fable 5 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
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
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
RustDeskandClaude Opus 5 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
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
RustDeskandClaude Opus 5 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
RustDeskandClaude Fable 5 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
rustdeskandClaude Fable 5 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
RustDeskandClaude Opus 5 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
RustDeskandClaude Opus 5 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
RustDeskcoderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>21pages
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
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
bmmh1andbmmh1 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
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 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
rustdesk 94a2a2bb4a fix https://github.com/rustdesk/rustdesk/issues/15566 2026-07-11 21:43:04 +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
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
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 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
rustdesk 435f6ec61d update copyright 2026-06-30 11:02:28 +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
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 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
rustdesk 16570ee34f fix https://github.com/rustdesk/rustdesk/discussions/15355 2026-06-22 22:57:08 +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
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