* fix(linux): a session logout should hand the peer to the login screen
Logging out closes every window in the session, the connection manager's
included, and its close handler kicks every peer with the reason a person
gets when they disconnect one by hand. That reason is the one thing the
client never retries on, so the remote session dies on a frozen frame
instead of reconnecting to the greeter that is already there.
The close carries nothing to tell the two apart: measured on KDE, the CM
receives no signal and logind still reports the session active at that
instant, and the server is killed within a few hundred ms either way, so
neither a state check nor a grace period can decide it. What is
distinguishable is the ACTION: disconnecting a peer is not the same event
as this window going away. So the window-close path now says so, and the
server ends the session without poisoning the retry; the Disconnect
button and the app's own close control keep kicking exactly as before.
Linux only, since that is where a logout closes the window.
Verified on plasma/sddm with a client attached: a logout now reconnects
to the greeter with no dialog, while closing the manager window still
shows Closed manually by the peer.
* fix(linux): close the tunnel too, and keep the web build compiling
Three seams the first pass missed. The web bridge is hand written, not
generated, so the new call needs its stub there or flutter build web
stops compiling - and that job is disabled in CI, so it would have gone
green. try_port_forward_loop is a second consumer of the same channel
and only knew Close, so a forwarded tunnel outlived the window it was
supposed to die with. And the variant had landed inside the DRM section,
whose comment says everything below it is drm-gated.
* 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>
* 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>
* 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>
* 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>
* 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>
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>
* fix: web, skip querying onlines, if not in main page
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix: web/mobile, skip querying onlines
Signed-off-by: fufesou <linlong1266@gmail.com>
* Set isInMainPage to false after router is changed.
Signed-off-by: fufesou <linlong1266@gmail.com>
---------
Signed-off-by: fufesou <linlong1266@gmail.com>
1. Web, build.
2. Web and mobile, `onSubmitted` for ID text field.
3. Web, remove unused key 'toggle_option'.
Signed-off-by: fufesou <linlong1266@gmail.com>