605 Commits

Author SHA1 Message Date
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
443 changed files with 42438 additions and 23852 deletions

View File

@@ -0,0 +1,56 @@
You are an expert in prompt engineering, specializing in optimizing AI code assistant instructions. Your task is to analyze and improve the instructions for Claude Code.
Follow these steps carefully:
1. Analysis Phase:
Review the chat history in your context window.
Then, examine the current Claude instructions, commands and config
<claude_instructions>
/CLAUDE.md
/.claude/commands/*
**/CLAUDE.md
.claude/settings.json
.claude/settings.local.json
</claude_instructions>
Analyze the chat history, instructions, commands and config to identify areas that could be improved. Look for:
- Inconsistencies in Claude's responses
- Misunderstandings of user requests
- Areas where Claude could provide more detailed or accurate information
- Opportunities to enhance Claude's ability to handle specific types of queries or tasks
- New commands or improvements to a commands name, function or response
- Permissions and MCPs we've approved locally that we should add to the config, especially if we've added new tools or require them for the command to work
2. Interaction Phase:
Present your findings and improvement ideas to the human. For each suggestion:
a) Explain the current issue you've identified
b) Propose a specific change or addition to the instructions
c) Describe how this change would improve Claude's performance
Wait for feedback from the human on each suggestion before proceeding. If the human approves a change, move it to the implementation phase. If not, refine your suggestion or move on to the next idea.
3. Implementation Phase:
For each approved change:
a) Clearly state the section of the instructions you're modifying
b) Present the new or modified text for that section
c) Explain how this change addresses the issue identified in the analysis phase
4. Output Format:
Present your final output in the following structure:
<analysis>
[List the issues identified and potential improvements]
</analysis>
<improvements>
[For each approved improvement:
1. Section being modified
2. New or modified instruction text
3. Explanation of how this addresses the identified issue]
</improvements>
<final_instructions>
[Present the complete, updated set of instructions for Claude, incorporating all approved changes]
</final_instructions>
Remember, your goal is to enhance Claude's performance and consistency while maintaining the core functionality and purpose of the AI assistant. Be thorough in your analysis, clear in your explanations, and precise in your implementations.

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

@@ -6,6 +6,7 @@ on:
workflow_call:
env:
CARGO_EXPAND_VERSION: "1.0.95"
FLUTTER_VERSION: "3.22.3"
FLUTTER_RUST_BRIDGE_VERSION: "1.80.1"
RUST_VERSION: "1.75" # https://github.com/rustdesk/rustdesk/discussions/7503
@@ -19,12 +20,14 @@ jobs:
job:
- {
target: x86_64-unknown-linux-gnu,
os: ubuntu-20.04,
os: ubuntu-22.04,
extra-build-args: "",
}
steps:
- name: Checkout source code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install prerequisites
run: |
@@ -37,9 +40,9 @@ jobs:
gcc \
git \
g++ \
libclang-10-dev \
libclang-dev \
libgtk-3-dev \
llvm-10-dev \
llvm-dev \
nasm \
ninja-build \
pkg-config \
@@ -73,6 +76,7 @@ jobs:
- 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

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:
@@ -45,6 +44,8 @@ jobs:
# steps:
# - name: Checkout source code
# uses: actions/checkout@v3
# with:
# submodules: recursive
# - name: Install rust toolchain (v${{ env.MIN_SUPPORTED_RUST_VERSION }})
# uses: actions-rs/toolchain@v1
@@ -80,7 +81,7 @@ 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: x86_64-unknown-linux-gnu , os: ubuntu-22.04 }
# - { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
steps:
- name: Export GitHub Actions cache environment variables
@@ -92,6 +93,8 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install prerequisites
shell: bash
@@ -108,6 +111,7 @@ jobs:
g++ \
libpam0g-dev \
libasound2-dev \
libunwind-dev \
libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-dev \
libgtk-3-dev \

View File

@@ -23,7 +23,7 @@ env:
MAC_RUST_VERSION: "1.81" # 1.81 is requred for macos, because of https://github.com/yury/cidre requires 1.81
CARGO_NDK_VERSION: "3.1.2"
SCITER_ARMV7_CMAKE_VERSION: "3.29.7"
SCITER_NASM_DEBVERSION: "2.14-1"
SCITER_NASM_DEBVERSION: "2.15.05-1"
LLVM_VERSION: "15.0.6"
FLUTTER_VERSION: "3.24.5"
ANDROID_FLUTTER_VERSION: "3.24.5"
@@ -31,17 +31,19 @@ env:
FLUTTER_ELINUX_VERSION: "3.16.9"
TAG_NAME: "${{ inputs.upload-tag }}"
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
# vcpkg version: 2024.11.16
VCPKG_COMMIT_ID: "b2cb0da531c2f1f740045bfe7c4dac59f0b2b69c"
VERSION: "1.3.6"
# vcpkg version: 2025.08.27
# If we change the `VCPKG COMMIT_ID`, please remember:
# 1. Call `$VCPKG_ROOT/vcpkg x-update-baseline` to update the baseline in `vcpkg.json`.
# Or we may face build issue like
# https://github.com/rustdesk/rustdesk/actions/runs/14414119794/job/40427970174
# 2. Update the `VCPKG_COMMIT_ID` in `ci.yml` and `playground.yml`.
VCPKG_COMMIT_ID: "120deac3062162151622ca4860575a33844ba10b"
ARMV7_VCPKG_COMMIT_ID: "6f29f12e82a8293156836ad81cc9bf5af41fe836" # 2025.01.13, got "/opt/artifacts/vcpkg/vcpkg: No such file or directory" with latest version
VERSION: "1.4.3"
NDK_VERSION: "r27c"
#signing keys env variable checks
ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}"
MACOS_P12_BASE64: "${{ secrets.MACOS_P12_BASE64 }}"
# To make a custom build with your own servers set the below secret values
RS_PUB_KEY: "${{ secrets.RS_PUB_KEY }}"
RENDEZVOUS_SERVER: "${{ secrets.RENDEZVOUS_SERVER }}"
API_SERVER: "${{ secrets.API_SERVER }}"
UPLOAD_ARTIFACT: "${{ inputs.upload-artifact }}"
SIGN_BASE_URL: "${{ secrets.SIGN_BASE_URL }}"
@@ -87,6 +89,8 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Restore bridge files
uses: actions/download-artifact@master
@@ -161,14 +165,44 @@ jobs:
- name: Build rustdesk
run: |
# Windows: build RustDesk
python3 .\build.py --portable --hwcodec --flutter --vram --skip-portable-pack
mv ./flutter/build/windows/x64/runner/Release ./rustdesk
# Download usbmmidd_v2.zip and extract it to ./rustdesk
Invoke-WebRequest -Uri https://github.com/rustdesk-org/rdev/releases/download/usbmmidd_v2/usbmmidd_v2.zip -OutFile usbmmidd_v2.zip
Expand-Archive usbmmidd_v2.zip -DestinationPath .
python3 .\build.py --portable --hwcodec --flutter --vram --skip-portable-pack
Remove-Item -Path usbmmidd_v2\Win32 -Recurse
Remove-Item -Path "usbmmidd_v2\deviceinstaller64.exe", "usbmmidd_v2\deviceinstaller.exe", "usbmmidd_v2\usbmmidd.bat"
mv ./flutter/build/windows/x64/runner/Release ./rustdesk
mv -Force .\usbmmidd_v2 ./rustdesk
# Download printer driver files and extract them to ./rustdesk
try {
Invoke-WebRequest -Uri https://github.com/rustdesk/hbb_common/releases/download/driver/rustdesk_printer_driver_v4-1.4.zip -OutFile rustdesk_printer_driver_v4-1.4.zip
Invoke-WebRequest -Uri https://github.com/rustdesk/hbb_common/releases/download/driver/printer_driver_adapter.zip -OutFile printer_driver_adapter.zip
Invoke-WebRequest -Uri https://github.com/rustdesk/hbb_common/releases/download/driver/sha256sums -OutFile sha256sums
# Check and move the files
$checksum_driver = (Select-String -Path .\sha256sums -Pattern '^([a-fA-F0-9]{64}) \*rustdesk_printer_driver_v4-1.4\.zip$').Matches.Groups[1].Value
$downloadsum_driver = Get-FileHash -Path rustdesk_printer_driver_v4-1.4.zip -Algorithm SHA256
$checksum_adapter = (Select-String -Path .\sha256sums -Pattern '^([a-fA-F0-9]{64}) \*printer_driver_adapter\.zip$').Matches.Groups[1].Value
$downloadsum_adapter = Get-FileHash -Path printer_driver_adapter.zip -Algorithm SHA256
if ($checksum_driver -eq $downloadsum_driver.Hash -and $checksum_adapter -eq $downloadsum_adapter.Hash) {
Write-Output "rustdesk_printer_driver_v4-1.4, checksums match, extract the file."
Expand-Archive rustdesk_printer_driver_v4-1.4.zip -DestinationPath .
mkdir ./rustdesk/drivers
mv -Force .\rustdesk_printer_driver_v4-1.4 ./rustdesk/drivers/RustDeskPrinterDriver
Expand-Archive printer_driver_adapter.zip -DestinationPath .
mv -Force .\printer_driver_adapter.dll ./rustdesk
} elseif ($checksum_driver -ne $downloadsum_driver.Hash) {
Write-Output "rustdesk_printer_driver_v4-1.4, checksums do not match, ignore the file."
} else {
Write-Output "printer_driver_adapter.dll, checksums do not match, ignore the file."
}
} catch {
Write-Host "Ingore the printer driver error."
}
- name: find Runner.res
# Windows: find Runner.res (compiled from ./flutter/windows/runner/Runner.rc), copy to ./Runner.res
# Runner.rc does not contain actual version, but Runner.res does
@@ -276,6 +310,8 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install LLVM and Clang
uses: rustdesk-org/install-llvm-action-32bit@master
@@ -356,6 +392,13 @@ jobs:
ls -l ./libs/portable/Runner.res;
fi
- name: Upload unsigned
if: env.UPLOAD_ARTIFACT == 'true'
uses: actions/upload-artifact@master
with:
name: rustdesk-unsigned-windows-${{ matrix.job.arch }}
path: Release
- name: Sign rustdesk files
if: env.UPLOAD_ARTIFACT == 'true' && env.SIGN_BASE_URL != ''
shell: bash
@@ -389,78 +432,6 @@ jobs:
files: |
./SignOutput/rustdesk-*.exe
build-for-macOS-arm64-selfhost:
# use build-for-macOS instead
if: false
runs-on: [self-hosted, macOS, ARM64]
needs: [generate-bridge]
steps:
- name: Export GitHub Actions cache environment variables
uses: actions/github-script@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
- name: Restore bridge files
uses: actions/download-artifact@master
with:
name: bridge-artifact
path: ./
- name: Build rustdesk
run: |
./build.py --flutter --hwcodec
- name: create unsigned dmg
if: env.UPLOAD_ARTIFACT == 'true'
run: |
CREATE_DMG="$(command -v create-dmg)"
CREATE_DMG="$(readlink -f "$CREATE_DMG")"
sed -i -e 's/MAXIMUM_UNMOUNTING_ATTEMPTS=3/MAXIMUM_UNMOUNTING_ATTEMPTS=7/' "$CREATE_DMG"
create-dmg --icon "RustDesk.app" 200 190 --hide-extension "RustDesk.app" --window-size 800 400 --app-drop-link 600 185 rustdesk-${{ env.VERSION }}-arm64.dmg ./flutter/build/macos/Build/Products/Release/RustDesk.app
- name: Upload unsigned macOS app
if: env.UPLOAD_ARTIFACT == 'true'
uses: actions/upload-artifact@master
with:
name: rustdesk-unsigned-macos-arm64
path: rustdesk-${{ env.VERSION }}-arm64.dmg # can not upload the directory directly or tar.gz file, which destroy the link structure, causing the codesign failed
- name: Codesign app and create signed dmg
if: env.MACOS_P12_BASE64 != null && env.UPLOAD_ARTIFACT == 'true'
run: |
# Patch create-dmg to give more attempts to unmount image
CREATE_DMG="$(command -v create-dmg)"
CREATE_DMG="$(readlink -f "$CREATE_DMG")"
sed -i -e 's/MAXIMUM_UNMOUNTING_ATTEMPTS=3/MAXIMUM_UNMOUNTING_ATTEMPTS=7/' "$CREATE_DMG"
# start sign the rustdesk.app and dmg
rm -rf *.dmg || true
codesign --force --options runtime -s ${{ secrets.MACOS_CODESIGN_IDENTITY }} --deep --strict ./flutter/build/macos/Build/Products/Release/RustDesk.app -vvv
create-dmg --icon "RustDesk.app" 200 190 --hide-extension "RustDesk.app" --window-size 800 400 --app-drop-link 600 185 rustdesk-${{ env.VERSION }}.dmg ./flutter/build/macos/Build/Products/Release/RustDesk.app
codesign --force --options runtime -s ${{ secrets.MACOS_CODESIGN_IDENTITY }} --deep --strict rustdesk-${{ env.VERSION }}.dmg -vvv
# notarize the rustdesk-${{ env.VERSION }}.dmg
rcodesign notary-submit --api-key-path ~/.p12/api-key.json --staple rustdesk-${{ env.VERSION }}.dmg
- name: Rename rustdesk
if: env.UPLOAD_ARTIFACT == 'true'
run: |
for name in rustdesk*??.dmg; do
mv "$name" "${name%%.dmg}-aarch64.dmg"
done
- name: Publish DMG package
if: env.UPLOAD_ARTIFACT == 'true'
uses: softprops/action-gh-release@v1
with:
prerelease: true
tag_name: ${{ env.TAG_NAME }}
files: |
rustdesk*-aarch64.dmg
build-rustdesk-ios:
if: ${{ inputs.upload-artifact }}
name: build rustdesk ios ipa
@@ -489,6 +460,9 @@ jobs:
brew install nasm yasm
- name: Checkout source code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install flutter
uses: subosito/flutter-action@v2
with:
@@ -546,6 +520,12 @@ jobs:
run: |
rustup target add ${{ matrix.job.target }}
cargo build --features flutter,hwcodec --release --target aarch64-apple-ios --lib
- name: Upload liblibrustdesk.a Artifacts
uses: actions/upload-artifact@master
with:
name: liblibrustdesk.a
path: target/aarch64-apple-ios/release/liblibrustdesk.a
- name: Build rustdesk
shell: bash
@@ -571,61 +551,6 @@ jobs:
# files: |
# flutter/build/ios/ipa/*.ipa
build-rustdesk-ios-selfhost:
#if: ${{ inputs.upload-artifact }}
if: false
runs-on: [self-hosted, macOS, ARM64]
needs: [generate-bridge]
strategy:
fail-fast: false
steps:
- name: Export GitHub Actions cache environment variables
uses: actions/github-script@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
# $VCPKG_ROOT/vcpkg install --triplet arm64-ios --x-install-root="$VCPKG_ROOT/installed"
- name: Restore bridge files
uses: actions/download-artifact@master
with:
name: bridge-artifact
path: ./
- name: Build rustdesk lib
run: |
cargo build --features flutter,hwcodec --release --target aarch64-apple-ios --lib
- name: Build rustdesk
# ios sdk not installed on this machine, I will install it later after I am back home
if: false
shell: bash
run: |
pushd flutter
# flutter build ipa --release --obfuscate --split-debug-info=./split-debug-info --no-codesign
# for easy debugging
flutter build ipa --release --no-codesign
# - name: Upload Artifacts
# # if: env.ANDROID_SIGNING_KEY != null && env.UPLOAD_ARTIFACT == 'true'
# uses: actions/upload-artifact@master
# with:
# name: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.apk
# path: flutter/build/ios/ipa/*.ipa
# - name: Publish ipa package
# # if: env.ANDROID_SIGNING_KEY != null && env.UPLOAD_ARTIFACT == 'true'
# uses: softprops/action-gh-release@v1
# with:
# prerelease: true
# tag_name: ${{ env.TAG_NAME }}
# files: |
# flutter/build/ios/ipa/*.ipa
build-for-macOS:
name: ${{ matrix.job.target }}
@@ -644,7 +569,7 @@ jobs:
}
- {
target: aarch64-apple-darwin,
os: macos-latest,
os: macos-14,
# extra-build-args: "--disable-flutter-texture-render", # disable this for mac, because we see a lot of users reporting flickering both on arm and x64, and we can not confirm if texture rendering has better performance if htere is no vram, https://github.com/rustdesk/rustdesk/issues/6296
extra-build-args: "--screencapturekit",
arch: aarch64,
@@ -660,6 +585,8 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Import the codesign cert
if: env.MACOS_P12_BASE64 != null
@@ -696,7 +623,7 @@ jobs:
- name: Install build runtime
run: |
brew install llvm create-dmg nasm cmake gcc wget ninja
brew install llvm create-dmg nasm
# pkg-config is handled in a separate step, because it may be already installed by `macos-latest`(14.7.1) runner
if command -v pkg-config &>/dev/null; then
echo "pkg-config is already installed"
@@ -781,7 +708,7 @@ jobs:
sed -i -e "s/osx_minimum_system_version = \"[0-9]*.[0-9]*\"/osx_minimum_system_version = \"${MIN_MACOS_VERSION}\"/" Cargo.toml
sed -i -e "s/MACOSX_DEPLOYMENT_TARGET = [0-9]*.[0-9]*;/MACOSX_DEPLOYMENT_TARGET = ${MIN_MACOS_VERSION};/" flutter/macos/Runner.xcodeproj/project.pbxproj
fi
./build.py --flutter --hwcodec ${{ matrix.job.extra-build-args }}
./build.py --flutter --hwcodec --unix-file-copy-paste ${{ matrix.job.extra-build-args }}
- name: create unsigned dmg
if: env.UPLOAD_ARTIFACT == 'true'
@@ -836,6 +763,7 @@ jobs:
needs:
- build-for-macOS
- build-for-windows-flutter
- build-for-windows-sciter
runs-on: ubuntu-latest
if: ${{ inputs.upload-artifact }}
steps:
@@ -857,9 +785,15 @@ jobs:
name: rustdesk-unsigned-windows-x86_64
path: ./windows-x86_64/
- name: Download Artifacts
uses: actions/download-artifact@master
with:
name: rustdesk-unsigned-windows-x86
path: ./windows-x86/
- name: Combine unsigned app
run: |
tar czf rustdesk-${{ env.VERSION }}-unsigned.tar.gz *.dmg windows-x86_64
tar czf rustdesk-${{ env.VERSION }}-unsigned.tar.gz *.dmg windows-x86_64 windows-x86
- name: Publish unsigned app
uses: softprops/action-gh-release@v1
@@ -879,21 +813,21 @@ jobs:
- {
arch: aarch64,
target: aarch64-linux-android,
os: ubuntu-20.04,
os: ubuntu-24.04,
reltype: release,
suffix: "",
}
- {
arch: armv7,
target: armv7-linux-androideabi,
os: ubuntu-20.04,
os: ubuntu-24.04,
reltype: release,
suffix: "",
}
- {
arch: x86_64,
target: x86_64-linux-android,
os: ubuntu-20.04,
os: ubuntu-24.04,
reltype: release,
suffix: "",
}
@@ -930,7 +864,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 \
@@ -942,7 +877,7 @@ jobs:
libxcb-xfixes0-dev \
libxdo-dev \
libxfixes-dev \
llvm-10-dev \
llvm-dev \
nasm \
ninja-build \
openjdk-17-jdk-headless \
@@ -952,6 +887,9 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install flutter
uses: subosito/flutter-action@v2
with:
@@ -1021,16 +959,6 @@ jobs:
prefix-key: rustdesk-lib-cache-android # TODO: drop '-android' part after caches are invalidated
key: ${{ matrix.job.target }}
- name: fix android for flutter 3.13
if: ${{ env.ANDROID_FLUTTER_VERSION == '3.13.9' }}
run: |
cd flutter
sed -i 's/uni_links_desktop/#uni_links_desktop/g' pubspec.yaml
sed -i 's/extended_text: .*/extended_text: 11.1.0/' pubspec.yaml
flutter pub get
cd lib
find . | grep dart | xargs sed -i 's/textScaler: TextScaler.linear(\(.*\)),/textScaleFactor: \1,/g'
- name: Build rustdesk lib
env:
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
@@ -1168,7 +1096,7 @@ jobs:
needs: [build-rustdesk-android]
name: build rustdesk android universal apk
if: ${{ inputs.upload-artifact }}
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
env:
reltype: release
x86_target: "" # can be ",android-x86"
@@ -1206,7 +1134,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 \
@@ -1218,7 +1147,7 @@ jobs:
libxcb-xfixes0-dev \
libxdo-dev \
libxfixes-dev \
llvm-10-dev \
llvm-dev \
nasm \
ninja-build \
openjdk-17-jdk-headless \
@@ -1228,6 +1157,9 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install flutter
uses: subosito/flutter-action@v2
with:
@@ -1270,16 +1202,6 @@ jobs:
name: librustdesk.so.i686-linux-android
path: ./flutter/android/app/src/main/jniLibs/x86
- name: fix android for flutter 3.13
if: ${{ env.ANDROID_FLUTTER_VERSION == '3.13.9' }}
run: |
cd flutter
sed -i 's/uni_links_desktop/#uni_links_desktop/g' pubspec.yaml
sed -i 's/extended_text: .*/extended_text: 11.1.0/' pubspec.yaml
flutter pub get
cd lib
find . | grep dart | xargs sed -i 's/textScaler: TextScaler.linear(\(.*\)),/textScaleFactor: \1,/g'
- name: Build rustdesk
shell: bash
env:
@@ -1365,7 +1287,7 @@ jobs:
arch: x86_64,
target: x86_64-unknown-linux-gnu,
distro: ubuntu18.04,
on: ubuntu-20.04,
on: ubuntu-22.04,
deb_arch: amd64,
vcpkg-triplet: x64-linux,
}
@@ -1373,7 +1295,7 @@ jobs:
arch: aarch64,
target: aarch64-unknown-linux-gnu,
distro: ubuntu18.04,
on: [self-hosted, Linux, ARM64],
on: ubuntu-22.04-arm,
deb_arch: arm64,
vcpkg-triplet: arm64-linux,
}
@@ -1386,16 +1308,20 @@ jobs:
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
- name: Maximize build space
if: ${{ matrix.job.arch == 'x86_64' }}
run: |
sudo rm -rf /opt/ghc
sudo rm -rf /usr/local/lib/android
sudo rm -rf /usr/share/dotnet
sudo apt-get update -y
sudo apt-get install -y nasm qemu-user-static
sudo apt-get install -y nasm
if [[ "${{ matrix.job.arch }}" == "x86_64" ]]; then
sudo apt-get install -y qemu-user-static
fi
- name: Checkout source code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set Swap Space
if: ${{ matrix.job.arch == 'x86_64' }}
@@ -1549,7 +1475,7 @@ jobs:
export JOBS=""
fi
echo $JOBS
cargo build --lib $JOBS --features hwcodec,flutter --release
cargo build --lib $JOBS --features hwcodec,flutter,unix-file-copy-paste --release
rm -rf target/release/deps target/release/build
rm -rf ~/.cargo
@@ -1686,7 +1612,6 @@ jobs:
build-rustdesk-linux-sciter:
if: ${{ inputs.upload-artifact }}
needs: build-rustdesk-linux # not for dep, just make it run later for parallelism
runs-on: ${{ matrix.job.on }}
name: build-rustdesk-linux-sciter ${{ matrix.job.target }}
strategy:
@@ -1697,22 +1622,22 @@ jobs:
- {
arch: x86_64,
target: x86_64-unknown-linux-gnu,
on: ubuntu-20.04,
on: ubuntu-22.04,
distro: ubuntu18.04,
deb_arch: amd64,
sciter_arch: x64,
vcpkg-triplet: x64-linux,
extra_features: ",hwcodec",
extra_features: ",hwcodec,unix-file-copy-paste",
}
- {
arch: armv7,
target: armv7-unknown-linux-gnueabihf,
on: [self-hosted, Linux, ARM64],
on: ubuntu-22.04-arm,
distro: ubuntu18.04-rustdesk,
deb_arch: armhf,
sciter_arch: arm32,
vcpkg-triplet: arm-linux,
extra_features: "",
extra_features: ",unix-file-copy-paste",
}
steps:
- name: Export GitHub Actions cache environment variables
@@ -1724,6 +1649,16 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Modify vcpkg.json for armv7
if: matrix.job.vcpkg-triplet == 'arm-linux'
run: |
# Replace the baseline in vcpkg.json with ARMV7_VCPKG_COMMIT_ID for armv7 builds
sed -i 's/"baseline": ".*"/"baseline": "${{ env.ARMV7_VCPKG_COMMIT_ID }}"/' vcpkg.json
echo "Modified vcpkg.json for armv7 build:"
grep -A 2 -B 2 '"baseline"' vcpkg.json
- name: Free Space
run: |
@@ -1810,11 +1745,12 @@ jobs:
rm -rf vcpkg
git clone https://github.com/microsoft/vcpkg
pushd vcpkg
git reset --hard ${{ env.VCPKG_COMMIT_ID }}
# build vcpkg helper executable with gcc-8 for arm-linux but use prebuilt one on x64-linux
if [ "${{ matrix.job.vcpkg-triplet }}" = "arm-linux" ]; then
git reset --hard ${{ env.ARMV7_VCPKG_COMMIT_ID }}
CC=/usr/bin/gcc-8 CXX=/usr/bin/g++-8 sh bootstrap-vcpkg.sh -disableMetrics
else
git reset --hard ${{ env.VCPKG_COMMIT_ID }}
sh bootstrap-vcpkg.sh -disableMetrics
fi
popd
@@ -1903,7 +1839,7 @@ jobs:
build-appimage:
name: Build appimage ${{ matrix.job.target }}
needs: [build-rustdesk-linux]
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
if: ${{ inputs.upload-artifact }}
strategy:
fail-fast: false
@@ -1914,6 +1850,8 @@ jobs:
steps:
- name: Checkout source code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Download Binary
uses: actions/download-artifact@master
@@ -1930,13 +1868,11 @@ jobs:
run: |
# install libarchive-tools for bsdtar command used in AppImageBuilder.yml
sudo apt-get update -y
sudo apt-get install -y libarchive-tools
# https://github.com/AppImage/AppImageKit/wiki/FUSE
sudo apt-get install -y libarchive-tools libfuse2
# set-up appimage-builder
pushd /tmp
wget -O appimage-builder-x86_64.AppImage https://github.com/AppImageCrafters/appimage-builder/releases/download/v1.1.0/appimage-builder-1.1.0-x86_64.AppImage
chmod +x appimage-builder-x86_64.AppImage
sudo mv appimage-builder-x86_64.AppImage /usr/local/bin/appimage-builder
popd
# https://github.com/AppImage/AppImageKit/issues/1395
sudo pip3 install git+https://github.com/rustdesk-org/appimage-builder.git
# run appimage-builder
pushd appimage
sudo appimage-builder --skip-tests --recipe ./AppImageBuilder-${{ matrix.job.arch }}.yml
@@ -1963,15 +1899,16 @@ jobs:
job:
- {
target: x86_64-unknown-linux-gnu,
distro: ubuntu18.04,
on: ubuntu-20.04,
# https://github.com/ostreedev/ostree/commit/4bac96a8c817beda37448f9b8c662162bb619981
distro: ubuntu22.04,
on: ubuntu-22.04,
arch: x86_64,
suffix: "",
}
- {
target: x86_64-unknown-linux-gnu,
distro: ubuntu18.04,
on: ubuntu-20.04,
distro: ubuntu22.04,
on: ubuntu-22.04,
arch: x86_64,
suffix: "-sciter",
}
@@ -1979,13 +1916,15 @@ jobs:
target: aarch64-unknown-linux-gnu,
# try out newer flatpak since error of "error: Nothing matches org.freedesktop.Platform in remote flathub"
distro: ubuntu22.04,
on: [self-hosted, Linux, ARM64],
on: ubuntu-22.04-arm,
arch: aarch64,
suffix: "",
}
steps:
- name: Checkout source code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Download Binary
uses: actions/download-artifact@master
@@ -2035,7 +1974,9 @@ jobs:
build-rustdesk-web:
if: False
name: build-rustdesk-web
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
permissions:
contents: read
strategy:
fail-fast: false
env:
@@ -2043,6 +1984,8 @@ jobs:
steps:
- name: Checkout source code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Prepare env
run: |

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.3"
NDK_VERSION: "r26d"
#signing keys env variable checks
ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}"
@@ -90,7 +89,8 @@ jobs:
uses: actions/checkout@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
@@ -126,7 +126,7 @@ 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
@@ -241,7 +241,7 @@ jobs:
- {
arch: aarch64,
target: aarch64-linux-android,
os: ubuntu-20.04,
os: ubuntu-22.04,
openssl-arch: android-arm64,
ref: master, # latest
}
@@ -250,6 +250,7 @@ jobs:
uses: actions/checkout@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 \

View File

@@ -2,6 +2,7 @@ name: Publish to WinGet
on:
release:
types: [released]
workflow_dispatch:
jobs:
publish:
runs-on: ubuntu-latest
@@ -9,5 +10,6 @@ jobs:
- uses: vedantmgoyal9/winget-releaser@main
with:
identifier: RustDesk.RustDesk
version: ${{ github.event.release.tag_name }}
version: "1.4.3"
release-tag: "1.4.3"
token: ${{ secrets.WINGET_TOKEN }}

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

91
CLAUDE.md Normal file
View File

@@ -0,0 +1,91 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Development Commands
### Build Commands
- `cargo run` - Build and run the desktop application (requires libsciter library)
- `python3 build.py --flutter` - Build Flutter version (desktop)
- `python3 build.py --flutter --release` - Build Flutter version in release mode
- `python3 build.py --hwcodec` - Build with hardware codec support
- `python3 build.py --vram` - Build with VRAM feature (Windows only)
- `cargo build --release` - Build Rust binary in release mode
- `cargo build --features hwcodec` - Build with specific features
### Flutter Mobile Commands
- `cd flutter && flutter build android` - Build Android APK
- `cd flutter && flutter build ios` - Build iOS app
- `cd flutter && flutter run` - Run Flutter app in development mode
- `cd flutter && flutter test` - Run Flutter tests
### Testing
- `cargo test` - Run Rust tests
- `cd flutter && flutter test` - Run Flutter tests
### Platform-Specific Build Scripts
- `flutter/build_android.sh` - Android build script
- `flutter/build_ios.sh` - iOS build script
- `flutter/build_fdroid.sh` - F-Droid build script
## Project Architecture
### Directory Structure
- **`src/`** - Main Rust application code
- `src/ui/` - Legacy Sciter UI (deprecated, use Flutter instead)
- `src/server/` - Audio/clipboard/input/video services and network connections
- `src/client.rs` - Peer connection handling
- `src/platform/` - Platform-specific code
- **`flutter/`** - Flutter UI code for desktop and mobile
- **`libs/`** - Core libraries
- `libs/hbb_common/` - Video codec, config, network wrapper, protobuf, file transfer utilities
- `libs/scrap/` - Screen capture functionality
- `libs/enigo/` - Platform-specific keyboard/mouse control
- `libs/clipboard/` - Cross-platform clipboard implementation
### 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/`
## Important Build Notes
### Dependencies
- Requires vcpkg for C++ dependencies: `libvpx`, `libyuv`, `opus`, `aom`
- Set `VCPKG_ROOT` environment variable
- Download appropriate Sciter library for legacy UI support
### Ignore Patterns
When working with files, ignore these directories:
- `target/` - Rust build artifacts
- `flutter/build/` - Flutter build output
- `flutter/.dart_tool/` - Flutter tooling files
### Cross-Platform Considerations
- Windows builds require additional DLLs and virtual display drivers
- macOS builds need proper signing and notarization for distribution
- Linux builds support multiple package formats (deb, rpm, AppImage)
- Mobile builds require platform-specific toolchains (Android SDK, Xcode)
### Feature Flags
- `hwcodec` - Hardware video encoding/decoding
- `vram` - VRAM optimization (Windows only)
- `flutter` - Enable Flutter UI
- `unix-file-copy-paste` - Unix file clipboard support
- `screencapturekit` - macOS ScreenCaptureKit (macOS only)
### Config
All configurations or options are under `libs/hbb_common/src/config.rs` file, 4 types:
- Settings
- Local
- Display
- Built-in

2983
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.3"
authors = ["rustdesk <info@rustdesk.com>"]
edition = "2021"
build= "build.rs"
@@ -16,6 +16,10 @@ crate-type = ["cdylib", "staticlib", "rlib"]
name = "naming"
path = "src/naming.rs"
[[bin]]
name = "service"
path = "src/service.rs"
[features]
inline = []
cli = []
@@ -42,7 +46,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"
@@ -78,7 +81,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"}
[target.'cfg(not(target_os = "linux"))'.dependencies]
# https://github.com/rustdesk/rustdesk/discussions/10197, not use cpal on linux
cpal = { git = "https://github.com/rustdesk-org/cpal", branch = "osx-screencapturekit" }
@@ -91,9 +95,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,13 +117,22 @@ winapi = { version = "0.3", features = [
"cguid",
"cfgmgr32",
"ioapiset",
"winspool",
] }
windows = { version = "0.61", features = [
"Win32",
"Win32_System",
"Win32_System_Diagnostics",
"Win32_System_Threading",
"Win32_System_Diagnostics_ToolHelp",
] }
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"
tauri-winrt-notification = "0.1"
runas = "1.2"
[target.'cfg(target_os = "macos")'.dependencies]
@@ -130,6 +144,10 @@ 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" }
@@ -141,6 +159,11 @@ 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" }
tiny-skia = "0.11"
softbuffer = "0.4"
fontdb = "0.23"
bytemuck = "1.23"
ttf-parser = "0.25"
[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
@@ -166,6 +189,8 @@ 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(target_os = "android")'.dependencies]
android_logger = "0.13"
@@ -173,11 +198,11 @@ 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"]
[package.metadata.winres]
LegalCopyright = "Copyright © 2024 Purslane Ltd. All rights reserved."
LegalCopyright = "Copyright © 2025 Purslane Ltd. All rights reserved."
ProductName = "RustDesk"
FileDescription = "RustDesk Remote Desktop"
OriginalFilename = "rustdesk.exe"
@@ -193,6 +218,7 @@ os-version = "0.2"
[dev-dependencies]
hound = "3.5"
docopt = "1.1"
[package.metadata.bundle]
name = "RustDesk"
@@ -208,7 +234,3 @@ panic = 'abort'
strip = true
#opt-level = 'z' # only have smaller size after strip
rpath = true
[profile.dev]
split-debuginfo = '...' # Platform-specific.
#strip = "debuginfo"

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)
@@ -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.3
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.3
exec: usr/share/rustdesk/rustdesk
exec_args: $@
apt:
@@ -102,3 +102,4 @@ AppDir:
AppImage:
arch: x86_64
update-information: guess
comp: gzip

View File

@@ -9,6 +9,7 @@ import shutil
import hashlib
import argparse
import sys
from pathlib import Path
windows = platform.platform().startswith('Windows')
osx = platform.platform().startswith(
@@ -354,7 +355,7 @@ def build_flutter_deb(version, features):
system2('mkdir -p tmpdeb/DEBIAN')
generate_control_file(version)
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/')
@@ -391,7 +392,7 @@ def build_deb_from_folder(version, binary_folder):
system2('mkdir -p tmpdeb/DEBIAN')
generate_control_file(version)
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/')
@@ -404,12 +405,13 @@ 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 --features {features} --release')
# copy dylib
system2(
"cp target/release/liblibrustdesk.dylib target/release/librustdesk.dylib")
os.chdir('flutter')
system2('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")
@@ -624,18 +626,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

@@ -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

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

@@ -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).

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,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

@@ -9,9 +9,14 @@
<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)
> [!Vorsicht]
> **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).

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).
@@ -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>]<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,9 +9,9 @@
<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).
@@ -165,6 +165,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

@@ -9,9 +9,9 @@
<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>
</p>
Converse conosco: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
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)
[![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-Recursos%20Avan%C3%A7ados-blue)](https://rustdesk.com/pricing.html)
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).
@@ -137,6 +137,10 @@ Por favor verifique que está executando estes comandos da raiz do repositório
- **[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
> [!Cuidadob]
> **Aviso de uso indevido:** <br>
> Os desenvolvedores do RustDesk não aprovam nem apoiam qualquer uso antiético ou ilegal deste software. O uso indevido, como acesso não autorizado, controle ou invasão de privacidade, é estritamente contra nossas diretrizes. Os autores não são responsáveis por qualquer uso indevido da aplicação.
## Screenshots
![image](https://user-images.githubusercontent.com/71636191/113112362-ae4deb80-923b-11eb-957d-ff88daad4f06.png)

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)

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

@@ -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

@@ -19,6 +19,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 +35,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
@@ -65,11 +71,14 @@ class InputService : AccessibilityService() {
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 +86,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 +96,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 +110,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 +143,11 @@ class InputService : AccessibilityService() {
}
if (mask == RIGHT_UP) {
longPress(mouseX, mouseY)
return
}
if (mask == BACK_UP) {
performGlobalAction(GLOBAL_ACTION_BACK)
return
}
@@ -241,18 +257,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 +371,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)

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() {
@@ -316,7 +322,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

@@ -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) {

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"

Binary file not shown.

BIN
flutter/assets/more.ttf Normal file

Binary file not shown.

View File

@@ -150,6 +150,10 @@ prebuild)
# Flutter used to compile Flutter<->Rust bridge files
CARGO_EXPAND_VERSION="$(yq -r \
.env.CARGO_EXPAND_VERSION \
.github/workflows/bridge.yml)"
FLUTTER_BRIDGE_VERSION="$(yq -r \
.env.FLUTTER_VERSION \
.github/workflows/bridge.yml)"
@@ -237,7 +241,10 @@ prebuild)
# Install rust bridge generator
cargo install cargo-expand
cargo install \
cargo-expand \
--version "${CARGO_EXPAND_VERSION}" \
--locked
cargo install flutter_rust_bridge_codegen \
--version "${FLUTTER_RUST_BRIDGE_VERSION}" \
--features "uuid" \

View File

@@ -4,4 +4,5 @@
# no obfuscate, because no easy to check errors
cd $(dirname $(dirname $(which flutter)))
git apply ~/rustdesk/.github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff
cd -
flutter build ipa --release

View File

@@ -1,14 +0,0 @@
#!/usr/bin/env bash
cd build/web/
python3 -c 'x=open("./main.dart.js", "rt").read();import re;y=re.search("https://.*canvaskit-wasm@([\d\.]+)/bin/",x);dirname="canvaskit@"+y.groups()[0];z=x.replace(y.group(),"/"+dirname+"/");f=open("./main.dart.js", "wt");f.write(z);import os;os.system("ln -s canvaskit " + dirname);'
mv jds/dist/index.js ./
mv jds/dist/vendor.js ./
/bin/rm -rf js
python3 -c 'import hashlib;x=hashlib.sha1(open("./main.dart.js").read().encode()).hexdigest()[:10];y=open("index.html","rt").read().replace("main.dart.js", "main.dart.js?v="+x);open("index.html","wt").write(y)'
python3 -c 'import hashlib;x=hashlib.sha1(open("./index.js").read().encode()).hexdigest()[:10];y=open("index.html","rt").read().replace("js/dist/index.js", "index.js?v="+x);open("index.html","wt").write(y)'
python3 -c 'import hashlib;x=hashlib.sha1(open("./vendor.js").read().encode()).hexdigest()[:10];y=open("index.html","rt").read().replace("js/dist/vendor.js", "vendor.js?v="+x);open("index.html","wt").write(y)'
tar czf x *
scp x sg:/tmp/
ssh sg "sudo tar xzf /tmp/x -C /var/www/html/web.rustdesk.com/ && /bin/rm /tmp/x && sudo chown www-data:www-data /var/www/html/web.rustdesk.com/ -R"
/bin/rm x
cd -

View File

@@ -43,6 +43,8 @@
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UIFileSharingEnabled</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
@@ -60,6 +62,8 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportsDocumentBrowser</key>
<true/>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>ITSAppUsesNonExemptEncryption</key>

View File

@@ -1,4 +1,2 @@
#!/usr/bin/env bash
cd $(dirname $(dirname $(which flutter)))
git apply ~/rustdesk/.github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff
cargo build --features flutter,hwcodec --release --target aarch64-apple-ios --lib

View File

@@ -13,11 +13,13 @@ import 'package:flutter_hbb/desktop/widgets/refresh_wrapper.dart';
import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart';
import 'package:flutter_hbb/main.dart';
import 'package:flutter_hbb/models/peer_model.dart';
import 'package:flutter_hbb/models/peer_tab_model.dart';
import 'package:flutter_hbb/models/state_model.dart';
import 'package:flutter_hbb/utils/multi_window_manager.dart';
import 'package:flutter_hbb/utils/platform_channel.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:get/get_rx/src/rx_workers/utils/debouncer.dart';
import 'package:provider/provider.dart';
import 'package:uni_links/uni_links.dart';
import 'package:url_launcher/url_launcher.dart';
@@ -29,8 +31,11 @@ import '../consts.dart';
import 'common/widgets/overlay.dart';
import 'mobile/pages/file_manager_page.dart';
import 'mobile/pages/remote_page.dart';
import 'mobile/pages/view_camera_page.dart';
import 'mobile/pages/terminal_page.dart';
import 'desktop/pages/remote_page.dart' as desktop_remote;
import 'desktop/pages/file_manager_page.dart' as desktop_file_manager;
import 'desktop/pages/view_camera_page.dart' as desktop_view_camera;
import 'package:flutter_hbb/desktop/widgets/remote_toolbar.dart';
import 'models/model.dart';
import 'models/platform_model.dart';
@@ -39,6 +44,7 @@ import 'package:flutter_hbb/native/win32.dart'
if (dart.library.html) 'package:flutter_hbb/web/win32.dart';
import 'package:flutter_hbb/native/common.dart'
if (dart.library.html) 'package:flutter_hbb/web/common.dart';
import 'package:http/http.dart' as http;
final globalKey = GlobalKey<NavigatorState>();
final navigationBarKey = GlobalKey();
@@ -71,6 +77,9 @@ bool _ignoreDevicePixelRatio = true;
int windowsBuildNumber = 0;
DesktopType? desktopType;
// Tolerance used for floating-point position comparisons to avoid precision errors.
const double _kPositionEpsilon = 1e-6;
bool get isMainDesktopWindow =>
desktopType == DesktopType.main || desktopType == DesktopType.cm;
@@ -96,13 +105,23 @@ enum DesktopType {
main,
remote,
fileTransfer,
viewCamera,
terminal,
cm,
portForward,
}
bool isDoubleEqual(double a, double b) {
return (a - b).abs() < _kPositionEpsilon;
}
class IconFont {
static const _family1 = 'Tabbar';
static const _family2 = 'PeerSearchbar';
static const _family3 = 'AddressBook';
static const _family4 = 'DeviceGroup';
static const _family5 = 'More';
IconFont._();
static const IconData max = IconData(0xe606, fontFamily: _family1);
@@ -113,8 +132,12 @@ class IconFont {
static const IconData menu = IconData(0xe628, fontFamily: _family1);
static const IconData search = IconData(0xe6a4, fontFamily: _family2);
static const IconData roundClose = IconData(0xe6ed, fontFamily: _family2);
static const IconData addressBook =
IconData(0xe602, fontFamily: "AddressBook");
static const IconData addressBook = IconData(0xe602, fontFamily: _family3);
static const IconData deviceGroupOutline =
IconData(0xe623, fontFamily: _family4);
static const IconData deviceGroupFill =
IconData(0xe748, fontFamily: _family4);
static const IconData more = IconData(0xe609, fontFamily: _family5);
}
class ColorThemeExtension extends ThemeExtension<ColorThemeExtension> {
@@ -817,7 +840,11 @@ class OverlayDialogManager {
close([res]) {
_dialogs.remove(dialogTag);
dialog.complete(res);
try {
dialog.complete(res);
} catch (e) {
debugPrint("Dialog complete catch error: $e");
}
BackButtonInterceptor.removeByName(dialogTag);
}
@@ -1137,15 +1164,23 @@ Widget createDialogContent(String text) {
void msgBox(SessionID sessionId, String type, String title, String text,
String link, OverlayDialogManager dialogManager,
{bool? hasCancel, ReconnectHandle? reconnect, int? reconnectTimeout}) {
{bool? hasCancel,
ReconnectHandle? reconnect,
int? reconnectTimeout,
VoidCallback? onSubmit,
int? submitTimeout}) {
dialogManager.dismissAll();
List<Widget> buttons = [];
bool hasOk = false;
submit() {
dialogManager.dismissAll();
// https://github.com/rustdesk/rustdesk/blob/5e9a31340b899822090a3731769ae79c6bf5f3e5/src/ui/common.tis#L263
if (!type.contains("custom") && desktopType != DesktopType.portForward) {
closeConnection();
if (onSubmit != null) {
onSubmit.call();
} else {
// https://github.com/rustdesk/rustdesk/blob/5e9a31340b899822090a3731769ae79c6bf5f3e5/src/ui/common.tis#L263
if (!type.contains("custom") && desktopType != DesktopType.portForward) {
closeConnection();
}
}
}
@@ -1161,7 +1196,18 @@ void msgBox(SessionID sessionId, String type, String title, String text,
if (type != "connecting" && type != "success" && !type.contains("nook")) {
hasOk = true;
buttons.insert(0, dialogButton('OK', onPressed: submit));
late final Widget btn;
if (submitTimeout != null) {
btn = _CountDownButton(
text: 'OK',
second: submitTimeout,
onPressed: submit,
submitOnTimeout: true,
);
} else {
btn = dialogButton('OK', onPressed: submit);
}
buttons.insert(0, btn);
}
hasCancel ??= !type.contains("error") &&
!type.contains("nocancel") &&
@@ -1182,7 +1228,8 @@ void msgBox(SessionID sessionId, String type, String title, String text,
reconnectTimeout != null) {
// `enabled` is used to disable the dialog button once the button is clicked.
final enabled = true.obs;
final button = Obx(() => _ReconnectCountDownButton(
final button = Obx(() => _CountDownButton(
text: 'Reconnect',
second: reconnectTimeout,
onPressed: enabled.isTrue
? () {
@@ -1536,7 +1583,9 @@ bool option2bool(String option, String value) {
String bool2option(String option, bool b) {
String res;
if (option.startsWith('enable-')) {
if (option.startsWith('enable-') &&
option != kOptionEnableUdpPunch &&
option != kOptionEnableIpv6Punch) {
res = b ? defaultOptionYes : 'N';
} else if (option.startsWith('allow-') ||
option == kOptionStopService ||
@@ -1544,7 +1593,9 @@ String bool2option(String option, bool b) {
option == kOptionForceAlwaysRelay) {
res = b ? 'Y' : defaultOptionNo;
} else {
assert(false);
if (option != kOptionEnableUdpPunch && option != kOptionEnableIpv6Punch) {
assert(false);
}
res = b ? 'Y' : 'N';
}
return res;
@@ -1580,7 +1631,8 @@ bool mainGetPeerBoolOptionSync(String id, String key) {
// Use `sessionGetToggleOption()` and `sessionToggleOption()` instead.
// Because all session options use `Y` and `<Empty>` as values.
Future<bool> matchPeer(String searchText, Peer peer) async {
Future<bool> matchPeer(
String searchText, Peer peer, PeerTabIndex peerTabIndex) async {
if (searchText.isEmpty) {
return true;
}
@@ -1591,11 +1643,14 @@ Future<bool> matchPeer(String searchText, Peer peer) async {
peer.username.toLowerCase().contains(searchText)) {
return true;
}
final alias = peer.alias;
if (alias.isEmpty) {
return false;
if (peer.alias.toLowerCase().contains(searchText)) {
return true;
}
return alias.toLowerCase().contains(searchText);
if (peerTabShowNote(peerTabIndex) &&
peer.note.toLowerCase().contains(searchText)) {
return true;
}
return false;
}
/// Get the image for the current [platform].
@@ -1625,6 +1680,16 @@ class LastWindowPosition {
LastWindowPosition(this.width, this.height, this.offsetWidth,
this.offsetHeight, this.isMaximized, this.isFullscreen);
bool equals(LastWindowPosition other) {
return (
(width == other.width) &&
(height == other.height) &&
(offsetWidth == other.offsetWidth) &&
(offsetHeight == other.offsetHeight) &&
(isMaximized == other.isMaximized) &&
(isFullscreen == other.isFullscreen));
}
Map<String, dynamic> toJson() {
return <String, dynamic>{
"width": width,
@@ -1664,24 +1729,36 @@ String get windowFramePrefix =>
? "incoming_"
: (bind.isOutgoingOnly() ? "outgoing_" : ""));
typedef WindowKey = ({WindowType type, int? windowId});
LastWindowPosition? _lastWindowPosition = null;
final Debouncer _saveWindowDebounce = Debouncer(delay: Duration(seconds: 1));
/// Save window position and size on exit
/// Note that windowId must be provided if it's subwindow
Future<void> saveWindowPosition(WindowType type, {int? windowId}) async {
Future<void> saveWindowPosition(WindowType type,
{int? windowId, bool? flush}) async {
if (type != WindowType.Main && windowId == null) {
debugPrint(
"Error: windowId cannot be null when saving positions for sub window");
}
late Offset position;
late Size sz;
Offset? position;
Size? sz;
late bool isMaximized;
bool isFullscreen = stateGlobal.fullscreen.isTrue;
setPreFrame() {
final pos = bind.getLocalFlutterOption(k: windowFramePrefix + type.name);
var lpos = LastWindowPosition.loadFromString(pos);
position = Offset(
lpos?.offsetWidth ?? position.dx, lpos?.offsetHeight ?? position.dy);
sz = Size(lpos?.width ?? sz.width, lpos?.height ?? sz.height);
if (lpos != null) {
if (lpos.offsetWidth != null && lpos.offsetHeight != null) {
position = Offset(lpos.offsetWidth!, lpos.offsetHeight!);
}
if (lpos.width != null && lpos.height != null) {
sz = Size(lpos.width!, lpos.height!);
}
}
}
switch (type) {
@@ -1721,29 +1798,54 @@ Future<void> saveWindowPosition(WindowType type, {int? windowId}) async {
}
break;
}
if (isWindows) {
if (isWindows && position != null) {
const kMinOffset = -10000;
const kMaxOffset = 10000;
if (position.dx < kMinOffset ||
position.dy < kMinOffset ||
position.dx > kMaxOffset ||
position.dy > kMaxOffset) {
if (position!.dx < kMinOffset ||
position!.dy < kMinOffset ||
position!.dx > kMaxOffset ||
position!.dy > kMaxOffset) {
debugPrint("Invalid position: $position, ignore saving position");
return;
}
}
final pos = LastWindowPosition(
sz.width, sz.height, position.dx, position.dy, isMaximized, isFullscreen);
debugPrint(
"Saving frame: $windowId: ${pos.width}/${pos.height}, offset:${pos.offsetWidth}/${pos.offsetHeight}, isMaximized:${pos.isMaximized}, isFullscreen:${pos.isFullscreen}");
final pos = LastWindowPosition(sz?.width, sz?.height, position?.dx,
position?.dy, isMaximized, isFullscreen);
await bind.setLocalFlutterOption(
k: windowFramePrefix + type.name, v: pos.toString());
final WindowKey key = (type: type, windowId: windowId);
if (type == WindowType.RemoteDesktop && windowId != null) {
await _saveSessionWindowPosition(
type, windowId, isMaximized, isFullscreen, pos);
final bool haveNewWindowPosition = (_lastWindowPosition == null) || !pos.equals(_lastWindowPosition!);
final bool isPreviousNewWindowPositionPending = _saveWindowDebounce.isRunning;
if (haveNewWindowPosition || isPreviousNewWindowPositionPending) {
_lastWindowPosition = pos;
if (flush ?? false) {
// If a previous update is pending, replace it.
_saveWindowDebounce.cancel();
await _saveWindowPositionActual(key);
} else if (haveNewWindowPosition) {
_saveWindowDebounce.call(() => _saveWindowPositionActual(key));
}
}
}
Future<void> _saveWindowPositionActual(WindowKey key) async {
LastWindowPosition? pos = _lastWindowPosition;
if (pos != null) {
debugPrint(
"Saving frame: ${key.windowId}: ${pos.width}/${pos.height}, offset:${pos.offsetWidth}/${pos.offsetHeight}, isMaximized:${pos.isMaximized}, isFullscreen:${pos.isFullscreen}");
await bind.setLocalFlutterOption(
k: windowFramePrefix + key.type.name, v: pos.toString());
if ((key.type == WindowType.RemoteDesktop || key.type == WindowType.ViewCamera) &&
key.windowId != null) {
await _saveSessionWindowPosition(
key.type, key.windowId!, pos.isMaximized ?? false, pos.isFullscreen ?? false, pos);
}
}
}
@@ -1809,6 +1911,8 @@ Future<Size> _adjustRestoreMainWindowSize(double? width, double? height) async {
return Size(restoreWidth, restoreHeight);
}
// Consider using Rect.contains() instead,
// though the implementation is not exactly the same.
bool isPointInRect(Offset point, Rect rect) {
return point.dx >= rect.left &&
point.dx <= rect.right &&
@@ -1892,7 +1996,9 @@ Future<bool> restoreWindowPosition(WindowType type,
String? pos;
// No need to check mainGetLocalBoolOptionSync(kOptionOpenNewConnInTabs)
// Though "open in tabs" is true and the new window restore peer position, it's ok.
if (type == WindowType.RemoteDesktop && windowId != null && peerId != null) {
if ((type == WindowType.RemoteDesktop || type == WindowType.ViewCamera) &&
windowId != null &&
peerId != null) {
final peerPos = bind.mainGetPeerFlutterOptionSync(
id: peerId, k: windowFramePrefix + type.name);
if (peerPos.isNotEmpty) {
@@ -1904,10 +2010,26 @@ Future<bool> restoreWindowPosition(WindowType type,
var lpos = LastWindowPosition.loadFromString(pos);
if (lpos == null) {
debugPrint("no window position saved, ignoring position restoration");
return false;
debugPrint("No window position saved, trying to center the window.");
switch (type) {
case WindowType.Main:
// Center the main window only if no position is saved (on first run).
if (isWindows || isLinux) {
await windowManager.center();
}
// For MacOS, the window is already centered by default.
// See https://github.com/rustdesk/rustdesk/blob/9b9276e7524523d7f667fefcd0694d981443df0e/flutter/macos/Runner/Base.lproj/MainMenu.xib#L333
// If `<windowPositionMask>` in `<window>` is not set, the window will be centered.
break;
default:
// No need to change the position of a sub window if no position is saved,
// since the default position is already centered.
// https://github.com/rustdesk/rustdesk/blob/317639169359936f7f9f85ef445ec9774218772d/flutter/lib/utils/multi_window_manager.dart#L163
break;
}
return true;
}
if (type == WindowType.RemoteDesktop) {
if (type == WindowType.RemoteDesktop || type == WindowType.ViewCamera) {
if (!isRemotePeerPos && windowId != null) {
if (lpos.offsetWidth != null) {
lpos.offsetWidth = lpos.offsetWidth! + windowId * kNewWindowOffset;
@@ -2076,8 +2198,14 @@ StreamSubscription? listenUniLinks({handleByFlutter = true}) {
enum UriLinkType {
remoteDesktop,
fileTransfer,
viewCamera,
portForward,
rdp,
terminal,
}
setEnvTerminalAdmin() {
bind.mainSetEnv(key: 'IS_TERMINAL_ADMIN', value: 'Y');
}
// uri link handler
@@ -2127,6 +2255,11 @@ bool handleUriLink({List<String>? cmdArgs, Uri? uri, String? uriString}) {
id = args[i + 1];
i++;
break;
case '--view-camera':
type = UriLinkType.viewCamera;
id = args[i + 1];
i++;
break;
case '--port-forward':
type = UriLinkType.portForward;
id = args[i + 1];
@@ -2137,6 +2270,17 @@ bool handleUriLink({List<String>? cmdArgs, Uri? uri, String? uriString}) {
id = args[i + 1];
i++;
break;
case '--terminal':
type = UriLinkType.terminal;
id = args[i + 1];
i++;
break;
case '--terminal-admin':
setEnvTerminalAdmin();
type = UriLinkType.terminal;
id = args[i + 1];
i++;
break;
case '--password':
password = args[i + 1];
i++;
@@ -2168,6 +2312,12 @@ bool handleUriLink({List<String>? cmdArgs, Uri? uri, String? uriString}) {
password: password, forceRelay: forceRelay);
});
break;
case UriLinkType.viewCamera:
Future.delayed(Duration.zero, () {
rustDeskWinManager.newViewCamera(id!,
password: password, forceRelay: forceRelay);
});
break;
case UriLinkType.portForward:
Future.delayed(Duration.zero, () {
rustDeskWinManager.newPortForward(id!, false,
@@ -2180,6 +2330,12 @@ bool handleUriLink({List<String>? cmdArgs, Uri? uri, String? uriString}) {
password: password, forceRelay: forceRelay);
});
break;
case UriLinkType.terminal:
Future.delayed(Duration.zero, () {
rustDeskWinManager.newTerminal(id!,
password: password, forceRelay: forceRelay);
});
break;
}
return true;
@@ -2191,7 +2347,16 @@ bool handleUriLink({List<String>? cmdArgs, Uri? uri, String? uriString}) {
List<String>? urlLinkToCmdArgs(Uri uri) {
String? command;
String? id;
final options = ["connect", "play", "file-transfer", "port-forward", "rdp"];
final options = [
"connect",
"play",
"file-transfer",
"view-camera",
"port-forward",
"rdp",
"terminal",
"terminal-admin",
];
if (uri.authority.isEmpty &&
uri.path.split('').every((char) => char == '/')) {
return [];
@@ -2219,19 +2384,10 @@ List<String>? urlLinkToCmdArgs(Uri uri) {
}
}
} else if (options.contains(uri.authority)) {
final optionIndex = options.indexOf(uri.authority);
command = '--${uri.authority}';
if (uri.path.length > 1) {
id = uri.path.substring(1);
}
if (isMobile && id != null) {
if (optionIndex == 0 || optionIndex == 1) {
connect(Get.context!, id);
} else if (optionIndex == 2) {
connect(Get.context!, id, isFileTransfer: true);
}
return null;
}
} else if (uri.authority.length > 2 &&
(uri.path.length <= 1 ||
(uri.path == '/r' || uri.path.startsWith('/r@')))) {
@@ -2255,12 +2411,29 @@ List<String>? urlLinkToCmdArgs(Uri uri) {
}
}
if (isMobile) {
if (id != null) {
final forceRelay = queryParameters["relay"] != null;
connect(Get.context!, id, forceRelay: forceRelay);
return null;
if (isMobile && id != null) {
final forceRelay = queryParameters["relay"] != null;
final password = queryParameters["password"];
// Determine connection type based on command
if (command == '--file-transfer') {
connect(Get.context!, id,
isFileTransfer: true, forceRelay: forceRelay, password: password);
} else if (command == '--view-camera') {
connect(Get.context!, id,
isViewCamera: true, forceRelay: forceRelay, password: password);
} else if (command == '--terminal') {
connect(Get.context!, id,
isTerminal: true, forceRelay: forceRelay, password: password);
} else if (command == 'terminal-admin') {
setEnvTerminalAdmin();
connect(Get.context!, id,
isTerminal: true, forceRelay: forceRelay, password: password);
} else {
// Default to remote desktop for '--connect', '--play', or direct connection
connect(Get.context!, id, forceRelay: forceRelay, password: password);
}
return null;
}
List<String> args = List.empty(growable: true);
@@ -2281,6 +2454,8 @@ List<String>? urlLinkToCmdArgs(Uri uri) {
connectMainDesktop(String id,
{required bool isFileTransfer,
required bool isViewCamera,
required bool isTerminal,
required bool isTcpTunneling,
required bool isRDP,
bool? forceRelay,
@@ -2293,12 +2468,24 @@ connectMainDesktop(String id,
isSharedPassword: isSharedPassword,
connToken: connToken,
forceRelay: forceRelay);
} else if (isViewCamera) {
await rustDeskWinManager.newViewCamera(id,
password: password,
isSharedPassword: isSharedPassword,
connToken: connToken,
forceRelay: forceRelay);
} else if (isTcpTunneling || isRDP) {
await rustDeskWinManager.newPortForward(id, isRDP,
password: password,
isSharedPassword: isSharedPassword,
connToken: connToken,
forceRelay: forceRelay);
} else if (isTerminal) {
await rustDeskWinManager.newTerminal(id,
password: password,
isSharedPassword: isSharedPassword,
connToken: connToken,
forceRelay: forceRelay);
} else {
await rustDeskWinManager.newRemoteDesktop(id,
password: password,
@@ -2309,10 +2496,13 @@ connectMainDesktop(String id,
/// Connect to a peer with [id].
/// If [isFileTransfer], starts a session only for file transfer.
/// If [isViewCamera], starts a session only for view camera.
/// If [isTcpTunneling], starts a session only for tcp tunneling.
/// If [isRDP], starts a session only for rdp.
connect(BuildContext context, String id,
{bool isFileTransfer = false,
bool isViewCamera = false,
bool isTerminal = false,
bool isTcpTunneling = false,
bool isRDP = false,
bool forceRelay = false,
@@ -2335,7 +2525,7 @@ connect(BuildContext context, String id,
id = id.replaceAll(' ', '');
final oldId = id;
id = await bind.mainHandleRelayId(id: id);
final forceRelay2 = id != oldId || forceRelay;
forceRelay = id != oldId || forceRelay;
assert(!(isFileTransfer && isTcpTunneling && isRDP),
"more than one connect type");
@@ -2344,16 +2534,20 @@ connect(BuildContext context, String id,
await connectMainDesktop(
id,
isFileTransfer: isFileTransfer,
isViewCamera: isViewCamera,
isTerminal: isTerminal,
isTcpTunneling: isTcpTunneling,
isRDP: isRDP,
password: password,
isSharedPassword: isSharedPassword,
forceRelay: forceRelay2,
forceRelay: forceRelay,
);
} else {
await rustDeskWinManager.call(WindowType.Main, kWindowConnect, {
'id': id,
'isFileTransfer': isFileTransfer,
'isViewCamera': isViewCamera,
'isTerminal': isTerminal,
'isTcpTunneling': isTcpTunneling,
'isRDP': isRDP,
'password': password,
@@ -2387,10 +2581,52 @@ connect(BuildContext context, String id,
context,
MaterialPageRoute(
builder: (BuildContext context) => FileManagerPage(
id: id, password: password, isSharedPassword: isSharedPassword),
id: id,
password: password,
isSharedPassword: isSharedPassword,
forceRelay: forceRelay),
),
);
}
} else if (isViewCamera) {
if (isWeb) {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) =>
desktop_view_camera.ViewCameraPage(
key: ValueKey(id),
id: id,
toolbarState: ToolbarState(),
password: password,
isSharedPassword: isSharedPassword,
),
),
);
} else {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => ViewCameraPage(
id: id,
password: password,
isSharedPassword: isSharedPassword,
forceRelay: forceRelay),
),
);
}
} else if (isTerminal) {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => TerminalPage(
id: id,
password: password,
isSharedPassword: isSharedPassword,
forceRelay: forceRelay,
),
),
);
} else {
if (isWeb) {
Navigator.push(
@@ -2401,7 +2637,6 @@ connect(BuildContext context, String id,
id: id,
toolbarState: ToolbarState(),
password: password,
forceRelay: forceRelay,
isSharedPassword: isSharedPassword,
),
),
@@ -2411,7 +2646,10 @@ connect(BuildContext context, String id,
context,
MaterialPageRoute(
builder: (BuildContext context) => RemotePage(
id: id, password: password, isSharedPassword: isSharedPassword),
id: id,
password: password,
isSharedPassword: isSharedPassword,
forceRelay: forceRelay),
),
);
}
@@ -2566,6 +2804,8 @@ bool get kUseCompatibleUiMode =>
isWindows &&
const [WindowsTarget.w7].contains(windowsBuildNumber.windowsVersion);
bool get isWin10 => windowsBuildNumber.windowsVersion == WindowsTarget.w10;
class ServerConfig {
late String idServer;
late String relayServer;
@@ -2591,7 +2831,7 @@ class ServerConfig {
} catch (err) {
final input = msg.split('').reversed.join('');
final bytes = base64Decode(base64.normalize(input));
json = jsonDecode(utf8.decode(bytes));
json = jsonDecode(utf8.decode(bytes, allowMalformed: true));
}
idServer = json['host'] ?? '';
relayServer = json['relay'] ?? '';
@@ -2675,6 +2915,8 @@ String getWindowName({WindowType? overrideType}) {
return name;
case WindowType.FileTransfer:
return "File Transfer - $name";
case WindowType.ViewCamera:
return "View Camera - $name";
case WindowType.PortForward:
return "Port Forward - $name";
case WindowType.RemoteDesktop:
@@ -2779,6 +3021,7 @@ Future<bool> canBeBlocked() async {
return access_mode == 'view' || (access_mode.isEmpty && !option);
}
// to-do: web not implemented
Future<void> shouldBeBlocked(RxBool block, WhetherUseRemoteBlock? use) async {
if (use != null && !await use()) {
block.value = false;
@@ -3040,6 +3283,7 @@ openMonitorInNewTabOrWindow(int i, String peerId, PeerInfo pi,
'peer_id': peerId,
'display': i,
'display_count': pi.displays.length,
'window_type': (kWindowType ?? WindowType.RemoteDesktop).index,
};
if (screenRect != null) {
args['screen_rect'] = {
@@ -3054,12 +3298,12 @@ openMonitorInNewTabOrWindow(int i, String peerId, PeerInfo pi,
}
setNewConnectWindowFrame(int windowId, String peerId, int preSessionCount,
int? display, Rect? screenRect) async {
WindowType windowType, int? display, Rect? screenRect) async {
if (screenRect == null) {
// Do not restore window position to new connection if there's a pre-session.
// https://github.com/rustdesk/rustdesk/discussions/8825
if (preSessionCount == 0) {
await restoreWindowPosition(WindowType.RemoteDesktop,
await restoreWindowPosition(windowType,
windowId: windowId, display: display, peerId: peerId);
}
} else {
@@ -3103,21 +3347,24 @@ parseParamScreenRect(Map<String, dynamic> params) {
get isInputSourceFlutter => stateGlobal.getInputSource() == "Input source 2";
class _ReconnectCountDownButton extends StatefulWidget {
_ReconnectCountDownButton({
class _CountDownButton extends StatefulWidget {
_CountDownButton({
Key? key,
required this.text,
required this.second,
required this.onPressed,
this.submitOnTimeout = false,
}) : super(key: key);
final String text;
final VoidCallback? onPressed;
final int second;
final bool submitOnTimeout;
@override
State<_ReconnectCountDownButton> createState() =>
_ReconnectCountDownButtonState();
State<_CountDownButton> createState() => _CountDownButtonState();
}
class _ReconnectCountDownButtonState extends State<_ReconnectCountDownButton> {
class _CountDownButtonState extends State<_CountDownButton> {
late int _countdownSeconds = widget.second;
Timer? _timer;
@@ -3138,6 +3385,9 @@ class _ReconnectCountDownButtonState extends State<_ReconnectCountDownButton> {
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
if (_countdownSeconds <= 0) {
timer.cancel();
if (widget.submitOnTimeout) {
widget.onPressed?.call();
}
} else {
setState(() {
_countdownSeconds--;
@@ -3149,7 +3399,7 @@ class _ReconnectCountDownButtonState extends State<_ReconnectCountDownButton> {
@override
Widget build(BuildContext context) {
return dialogButton(
'${translate('Reconnect')} (${_countdownSeconds}s)',
'${translate(widget.text)} (${_countdownSeconds}s)',
onPressed: widget.onPressed,
isOutline: true,
);
@@ -3339,6 +3589,9 @@ Color? disabledTextColor(BuildContext context, bool enabled) {
}
Widget loadPowered(BuildContext context) {
if (bind.mainGetBuildinOption(key: "hide-powered-by-me") == 'Y') {
return SizedBox.shrink();
}
return MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
@@ -3610,7 +3863,7 @@ void earlyAssert() {
}
void checkUpdate() {
if (isDesktop || isAndroid) {
if (!isWeb) {
if (!bind.isCustomClient()) {
platformFFI.registerEventHandler(
kCheckSoftwareUpdateFinish, kCheckSoftwareUpdateFinish,
@@ -3638,3 +3891,136 @@ extension WorkaroundFreezeLinuxMint on Widget {
}
}
}
// Don't use `extension` here, the border looks weird if using `extension` in my test.
Widget workaroundWindowBorder(BuildContext context, Widget child) {
if (!isWin10) {
return child;
}
final isLight = Theme.of(context).brightness == Brightness.light;
final borderColor = isLight ? Colors.black87 : Colors.grey;
final width = isLight ? 0.5 : 0.1;
getBorderWidget(Widget child) {
return Obx(() =>
(stateGlobal.isMaximized.isTrue || stateGlobal.fullscreen.isTrue)
? Offstage()
: child);
}
final List<Widget> borders = [
getBorderWidget(Container(
color: borderColor,
height: width + 0.1,
))
];
if (kWindowType == WindowType.Main && !isLight) {
borders.addAll([
getBorderWidget(Align(
alignment: Alignment.topLeft,
child: Container(
color: borderColor,
width: width,
),
)),
getBorderWidget(Align(
alignment: Alignment.topRight,
child: Container(
color: borderColor,
width: width,
),
)),
getBorderWidget(Align(
alignment: Alignment.bottomCenter,
child: Container(
color: borderColor,
height: width,
),
)),
]);
}
return Stack(
children: [
child,
...borders,
],
);
}
void updateTextAndPreserveSelection(
TextEditingController controller, String text) {
// Only care about select all for now.
final isSelected = controller.selection.isValid &&
controller.selection.end > controller.selection.start;
// Set text will make the selection invalid.
controller.text = text;
if (isSelected) {
controller.selection = TextSelection(
baseOffset: 0, extentOffset: controller.value.text.length);
}
}
List<String> getPrinterNames() {
final printerNamesJson = bind.mainGetPrinterNames();
if (printerNamesJson.isEmpty) {
return [];
}
try {
final List<dynamic> printerNamesList = jsonDecode(printerNamesJson);
final appPrinterName = '$appName Printer';
return printerNamesList
.map((e) => e.toString())
.where((name) => name != appPrinterName)
.toList();
} catch (e) {
debugPrint('failed to parse printer names, err: $e');
return [];
}
}
String _appName = '';
String get appName {
if (_appName.isEmpty) {
_appName = bind.mainGetAppNameSync();
}
return _appName;
}
String getConnectionText(bool secure, bool direct, String streamType) {
String connectionText;
if (secure && direct) {
connectionText = translate("Direct and encrypted connection");
} else if (secure && !direct) {
connectionText = translate("Relayed and encrypted connection");
} else if (!secure && direct) {
connectionText = translate("Direct and unencrypted connection");
} else {
connectionText = translate("Relayed and unencrypted connection");
}
if (streamType == 'Relay') {
streamType = 'TCP';
}
if (streamType.isEmpty) {
return connectionText;
} else {
return '$connectionText ($streamType)';
}
}
String decode_http_response(http.Response resp) {
try {
// https://github.com/rustdesk/rustdesk-server-pro/discussions/758
return utf8.decode(resp.bodyBytes, allowMalformed: true);
} catch (e) {
debugPrint('Failed to decode response as UTF-8: $e');
// Fallback to bodyString which handles encoding automatically
return resp.body;
}
}
bool peerTabShowNote(PeerTabIndex peerTabIndex) {
return peerTabIndex == PeerTabIndex.ab || peerTabIndex == PeerTabIndex.group;
}

View File

@@ -27,6 +27,7 @@ class UserPayload {
String name = '';
String email = '';
String note = '';
String? verifier;
UserStatus status;
bool isAdmin = false;
@@ -34,6 +35,7 @@ class UserPayload {
: name = json['name'] ?? '',
email = json['email'] ?? '',
note = json['note'] ?? '',
verifier = json['verifier'],
status = json['status'] == 0
? UserStatus.kDisabled
: json['status'] == -1
@@ -67,6 +69,7 @@ class PeerPayload {
int? status;
String user = '';
String user_name = '';
String? device_group_name;
String note = '';
PeerPayload.fromJson(Map<String, dynamic> json)
@@ -75,6 +78,7 @@ class PeerPayload {
status = json['status'],
user = json['user'] ?? '',
user_name = json['user_name'] ?? '',
device_group_name = json['device_group_name'] ?? '',
note = json['note'] ?? '';
static Peer toPeer(PeerPayload p) {
@@ -84,6 +88,8 @@ class PeerPayload {
"username": p.info['username'] ?? '',
"platform": _platform(p.info['os']),
"hostname": p.info['device_name'],
"device_group_name": p.device_group_name,
"note": p.note,
});
}
@@ -243,15 +249,17 @@ class AbProfile {
String name;
String owner;
String? note;
dynamic info;
int rule;
AbProfile(this.guid, this.name, this.owner, this.note, this.rule);
AbProfile(this.guid, this.name, this.owner, this.note, this.rule, this.info);
AbProfile.fromJson(Map<String, dynamic> json)
: guid = json['guid'] ?? '',
name = json['name'] ?? '',
owner = json['owner'] ?? '',
note = json['note'] ?? '',
info = json['info'],
rule = json['rule'] ?? 0;
}
@@ -265,3 +273,19 @@ class AbTag {
: name = json['name'] ?? '',
color = json['color'] ?? '';
}
class DeviceGroupPayload {
String name;
DeviceGroupPayload(this.name);
DeviceGroupPayload.fromJson(Map<String, dynamic> json)
: name = json['name'] ?? '';
Map<String, dynamic> toGroupCacheJson() {
final Map<String, dynamic> map = {
'name': name,
};
return map;
}
}

View File

@@ -77,9 +77,11 @@ class CurrentDisplayState {
class ConnectionType {
final Rx<String> _secure = kInvalidValueStr.obs;
final Rx<String> _direct = kInvalidValueStr.obs;
final Rx<String> _stream_type = kInvalidValueStr.obs;
Rx<String> get secure => _secure;
Rx<String> get direct => _direct;
Rx<String> get stream_type => _stream_type;
static String get strSecure => 'secure';
static String get strInsecure => 'insecure';
@@ -94,9 +96,14 @@ class ConnectionType {
_direct.value = v ? strDirect : strIndirect;
}
void setStreamType(String v) {
_stream_type.value = v;
}
bool isValid() {
return _secure.value != kInvalidValueStr &&
_direct.value != kInvalidValueStr;
_direct.value != kInvalidValueStr &&
_stream_type.value != kInvalidValueStr;
}
}

View File

@@ -466,6 +466,7 @@ class _AddressBookState extends State<AddressBook> {
IDTextEditingController idController = IDTextEditingController(text: '');
TextEditingController aliasController = TextEditingController(text: '');
TextEditingController passwordController = TextEditingController(text: '');
TextEditingController noteController = TextEditingController(text: '');
final tags = List.of(gFFI.abModel.currentAbTags);
var selectedTag = List<dynamic>.empty(growable: true).obs;
final style = TextStyle(fontSize: 14.0);
@@ -494,7 +495,11 @@ class _AddressBookState extends State<AddressBook> {
password = passwordController.text;
}
String? errMsg2 = await gFFI.abModel.addIdToCurrent(
id, aliasController.text.trim(), password, selectedTag);
id,
aliasController.text.trim(),
password,
selectedTag,
noteController.text);
if (errMsg2 != null) {
setState(() {
isInProgress = false;
@@ -509,13 +514,13 @@ class _AddressBookState extends State<AddressBook> {
double marginBottom = 4;
row({required Widget lable, required Widget input}) {
row({required Widget label, required Widget input}) {
makeChild(bool isPortrait) => Row(
children: [
!isPortrait
? ConstrainedBox(
constraints: const BoxConstraints(minWidth: 100),
child: lable.marginOnly(right: 10))
child: label.marginOnly(right: 10))
: SizedBox.shrink(),
Expanded(
child: ConstrainedBox(
@@ -535,7 +540,7 @@ class _AddressBookState extends State<AddressBook> {
Column(
children: [
row(
lable: Row(
label: Row(
children: [
Text(
'*',
@@ -558,7 +563,7 @@ class _AddressBookState extends State<AddressBook> {
errorMaxLines: 5),
).workaroundFreezeLinuxMint())),
row(
lable: Text(
label: Text(
translate('Alias'),
style: style,
),
@@ -573,7 +578,7 @@ class _AddressBookState extends State<AddressBook> {
),
if (isCurrentAbShared)
row(
lable: Text(
label: Text(
translate('Password'),
style: style,
),
@@ -600,6 +605,24 @@ class _AddressBookState extends State<AddressBook> {
),
).workaroundFreezeLinuxMint(),
)),
row(
label: Text(
translate('Note'),
style: style,
),
input: Obx(
() => TextField(
controller: noteController,
maxLines: 3,
minLines: 1,
maxLength: 300,
decoration: InputDecoration(
labelText: stateGlobal.isPortrait.isFalse
? null
: translate('Note'),
),
).workaroundFreezeLinuxMint(),
)),
if (gFFI.abModel.currentAbTags.isNotEmpty)
Align(
alignment: Alignment.centerLeft,

View File

@@ -1,4 +1,3 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_hbb/common/formatter/id_formatter.dart';
import '../../../models/platform_model.dart';
@@ -6,56 +5,104 @@ import 'package:flutter_hbb/models/peer_model.dart';
import 'package:flutter_hbb/common.dart';
import 'package:flutter_hbb/common/widgets/peer_card.dart';
Future<List<Peer>> getAllPeers() async {
Map<String, dynamic> recentPeers = jsonDecode(bind.mainLoadRecentPeersSync());
Map<String, dynamic> lanPeers = jsonDecode(bind.mainLoadLanPeersSync());
Map<String, dynamic> combinedPeers = {};
class AllPeersLoader {
List<Peer> peers = [];
void mergePeers(Map<String, dynamic> peers) {
if (peers.containsKey("peers")) {
dynamic peerData = peers["peers"];
bool _isPeersLoading = false;
bool _isPeersLoaded = false;
if (peerData is String) {
try {
peerData = jsonDecode(peerData);
} catch (e) {
print("Error decoding peers: $e");
return;
}
}
final String _listenerKey = 'AllPeersLoader';
if (peerData is List) {
for (var peer in peerData) {
if (peer is Map && peer.containsKey("id")) {
String id = peer["id"];
if (!combinedPeers.containsKey(id)) {
combinedPeers[id] = peer;
}
}
}
late void Function(VoidCallback) setState;
bool get needLoad => !_isPeersLoaded && !_isPeersLoading;
bool get isPeersLoaded => _isPeersLoaded;
AllPeersLoader();
void init(void Function(VoidCallback) setState) {
this.setState = setState;
gFFI.recentPeersModel.addListener(_mergeAllPeers);
gFFI.lanPeersModel.addListener(_mergeAllPeers);
gFFI.abModel.addPeerUpdateListener(_listenerKey, _mergeAllPeers);
gFFI.groupModel.addPeerUpdateListener(_listenerKey, _mergeAllPeers);
}
void clear() {
gFFI.recentPeersModel.removeListener(_mergeAllPeers);
gFFI.lanPeersModel.removeListener(_mergeAllPeers);
gFFI.abModel.removePeerUpdateListener(_listenerKey);
gFFI.groupModel.removePeerUpdateListener(_listenerKey);
}
Future<void> getAllPeers() async {
if (!needLoad) {
return;
}
_isPeersLoading = true;
if (gFFI.recentPeersModel.peers.isEmpty) {
bind.mainLoadRecentPeers();
}
if (gFFI.lanPeersModel.peers.isEmpty) {
bind.mainLoadLanPeers();
}
// No need to care about peers from abModel, and group model.
// Because they will pull data in `refreshCurrentUser()` on startup.
final startTime = DateTime.now();
_mergeAllPeers();
final diffTime = DateTime.now().difference(startTime).inMilliseconds;
if (diffTime < 100) {
await Future.delayed(Duration(milliseconds: diffTime));
}
}
void _mergeAllPeers() {
Map<String, dynamic> combinedPeers = {};
for (var p in gFFI.abModel.allPeers()) {
if (!combinedPeers.containsKey(p.id)) {
combinedPeers[p.id] = p.toJson();
}
}
}
mergePeers(recentPeers);
mergePeers(lanPeers);
for (var p in gFFI.abModel.allPeers()) {
if (!combinedPeers.containsKey(p.id)) {
combinedPeers[p.id] = p.toJson();
for (var p in gFFI.groupModel.peers.map((e) => Peer.copy(e)).toList()) {
if (!combinedPeers.containsKey(p.id)) {
combinedPeers[p.id] = p.toJson();
}
}
}
for (var p in gFFI.groupModel.peers.map((e) => Peer.copy(e)).toList()) {
if (!combinedPeers.containsKey(p.id)) {
combinedPeers[p.id] = p.toJson();
List<Peer> parsedPeers = [];
for (var peer in combinedPeers.values) {
parsedPeers.add(Peer.fromJson(peer));
}
}
List<Peer> parsedPeers = [];
Set<String> peerIds = combinedPeers.keys.toSet();
for (final peer in gFFI.lanPeersModel.peers) {
if (!peerIds.contains(peer.id)) {
parsedPeers.add(peer);
peerIds.add(peer.id);
}
}
for (var peer in combinedPeers.values) {
parsedPeers.add(Peer.fromJson(peer));
for (final peer in gFFI.recentPeersModel.peers) {
if (!peerIds.contains(peer.id)) {
parsedPeers.add(peer);
peerIds.add(peer.id);
}
}
for (final id in gFFI.recentPeersModel.restPeerIds) {
if (!peerIds.contains(id)) {
parsedPeers.add(Peer.fromJson({'id': id}));
peerIds.add(id);
}
}
peers = parsedPeers;
setState(() {
_isPeersLoading = false;
_isPeersLoaded = true;
});
}
return parsedPeers;
}
class AutocompletePeerTile extends StatefulWidget {

View File

@@ -4,7 +4,6 @@ import 'dart:convert';
import 'package:bot_toast/bot_toast.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_hbb/common/shared_state.dart';
import 'package:flutter_hbb/common/widgets/setting_widgets.dart';
import 'package:flutter_hbb/consts.dart';
@@ -71,7 +70,7 @@ void changeIdDialog() {
final rules = [
RegexValidationRule('starts with a letter', RegExp(r'^[a-zA-Z]')),
LengthRangeValidationRule(6, 16),
RegexValidationRule('allowed characters', RegExp(r'^\w*$'))
RegexValidationRule('allowed characters', RegExp(r'^[\w-]*$'))
];
gFFI.dialogManager.show((setState, close, context) {
@@ -412,24 +411,38 @@ class DialogTextField extends StatelessWidget {
return Row(
children: [
Expanded(
child: TextField(
decoration: InputDecoration(
labelText: title,
hintText: hintText,
prefixIcon: prefixIcon,
suffixIcon: suffixIcon,
helperText: helperText,
helperMaxLines: 8,
errorText: errorText,
errorMaxLines: 8,
),
controller: controller,
focusNode: focusNode,
autofocus: true,
obscureText: obscureText,
keyboardType: keyboardType,
inputFormatters: inputFormatters,
maxLength: maxLength,
child: Column(
children: [
TextField(
decoration: InputDecoration(
labelText: title,
hintText: hintText,
prefixIcon: prefixIcon,
suffixIcon: suffixIcon,
helperText: helperText,
helperMaxLines: 8,
),
controller: controller,
focusNode: focusNode,
autofocus: true,
obscureText: obscureText,
keyboardType: keyboardType,
inputFormatters: inputFormatters,
maxLength: maxLength,
),
if (errorText != null)
Align(
alignment: Alignment.centerLeft,
child: SelectableText(
errorText!,
style: TextStyle(
color: Theme.of(context).colorScheme.error,
fontSize: 12,
),
textAlign: TextAlign.left,
).paddingOnly(top: 8, left: 12),
),
],
).workaroundFreezeLinuxMint(),
),
],
@@ -806,23 +819,33 @@ void enterPasswordDialog(
}
void enterUserLoginDialog(
SessionID sessionId, OverlayDialogManager dialogManager) async {
SessionID sessionId,
OverlayDialogManager dialogManager,
String osAccountDescTip,
bool canRememberAccount) async {
await _connectDialog(
sessionId,
dialogManager,
osUsernameController: TextEditingController(),
osPasswordController: TextEditingController(),
osAccountDescTip: osAccountDescTip,
canRememberAccount: canRememberAccount,
);
}
void enterUserLoginAndPasswordDialog(
SessionID sessionId, OverlayDialogManager dialogManager) async {
SessionID sessionId,
OverlayDialogManager dialogManager,
String osAccountDescTip,
bool canRememberAccount) async {
await _connectDialog(
sessionId,
dialogManager,
osUsernameController: TextEditingController(),
osPasswordController: TextEditingController(),
passwordController: TextEditingController(),
osAccountDescTip: osAccountDescTip,
canRememberAccount: canRememberAccount,
);
}
@@ -832,17 +855,28 @@ _connectDialog(
TextEditingController? osUsernameController,
TextEditingController? osPasswordController,
TextEditingController? passwordController,
String? osAccountDescTip,
bool canRememberAccount = true,
}) async {
final errUsername = ''.obs;
var rememberPassword = false;
if (passwordController != null) {
rememberPassword =
await bind.sessionGetRemember(sessionId: sessionId) ?? false;
}
var rememberAccount = false;
if (osUsernameController != null) {
if (canRememberAccount && osUsernameController != null) {
rememberAccount =
await bind.sessionGetRemember(sessionId: sessionId) ?? false;
}
if (osUsernameController != null) {
osUsernameController.addListener(() {
if (errUsername.value.isNotEmpty) {
errUsername.value = '';
}
});
}
dialogManager.dismissAll();
dialogManager.show((setState, close, context) {
cancel() {
@@ -851,6 +885,13 @@ _connectDialog(
}
submit() {
if (osUsernameController != null) {
if (osUsernameController.text.trim().isEmpty) {
errUsername.value = translate('Empty Username');
setState(() {});
return;
}
}
final osUsername = osUsernameController?.text.trim() ?? '';
final osPassword = osPasswordController?.text.trim() ?? '';
final password = passwordController?.text.trim() ?? '';
@@ -914,26 +955,39 @@ _connectDialog(
}
return Column(
children: [
descWidget(translate('login_linux_tip')),
if (osAccountDescTip != null) descWidget(translate(osAccountDescTip)),
DialogTextField(
title: translate(DialogTextField.kUsernameTitle),
controller: osUsernameController,
prefixIcon: DialogTextField.kUsernameIcon,
errorText: null,
),
if (errUsername.value.isNotEmpty)
Align(
alignment: Alignment.centerLeft,
child: SelectableText(
errUsername.value,
style: TextStyle(
color: Theme.of(context).colorScheme.error,
fontSize: 12,
),
textAlign: TextAlign.left,
).paddingOnly(left: 12, bottom: 2),
),
PasswordWidget(
controller: osPasswordController,
autoFocus: false,
),
rememberWidget(
translate('remember_account_tip'),
rememberAccount,
(v) {
if (v != null) {
setState(() => rememberAccount = v);
}
},
),
if (canRememberAccount)
rememberWidget(
translate('remember_account_tip'),
rememberAccount,
(v) {
if (v != null) {
setState(() => rememberAccount = v);
}
},
),
],
);
}
@@ -1123,7 +1177,7 @@ void showRequestElevationDialog(
DialogTextField(
controller: userController,
title: translate('Username'),
hintText: translate('eg: admin'),
hintText: translate('elevation_username_tip'),
prefixIcon: DialogTextField.kUsernameIcon,
errorText: errUser.isEmpty ? null : errUser.value,
),
@@ -1610,6 +1664,28 @@ customImageQualityDialog(SessionID sessionId, String id, FFI ffi) async {
msgBoxCommon(ffi.dialogManager, 'Custom Image Quality', content, [btnClose]);
}
trackpadSpeedDialog(SessionID sessionId, FFI ffi) async {
int initSpeed = ffi.inputModel.trackpadSpeed;
final curSpeed = SimpleWrapper(initSpeed);
final btnClose = dialogButton('Close', onPressed: () async {
if (curSpeed.value <= kMaxTrackpadSpeed &&
curSpeed.value >= kMinTrackpadSpeed &&
curSpeed.value != initSpeed) {
await bind.sessionSetTrackpadSpeed(
sessionId: sessionId, value: curSpeed.value);
await ffi.inputModel.updateTrackpadSpeed();
}
ffi.dialogManager.dismissAll();
});
msgBoxCommon(
ffi.dialogManager,
'Trackpad speed',
TrackpadSpeedWidget(
value: curSpeed,
),
[btnClose]);
}
void deleteConfirmDialog(Function onSubmit, String title) async {
gFFI.dialogManager.show(
(setState, close, context) {
@@ -1707,6 +1783,49 @@ void editAbTagDialog(
});
}
void editAbPeerNoteDialog(String id) {
var isInProgress = false;
final currentNote = gFFI.abModel.getPeerNote(id);
var controller = TextEditingController(text: currentNote);
gFFI.dialogManager.show((setState, close, context) {
submit() async {
setState(() {
isInProgress = true;
});
await gFFI.abModel.changeNote(id: id, note: controller.text);
close();
}
return CustomAlertDialog(
title: Text(translate("Edit note")),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextField(
controller: controller,
autofocus: true,
maxLines: 3,
minLines: 1,
maxLength: 300,
decoration: InputDecoration(
labelText: translate('Note'),
),
).workaroundFreezeLinuxMint(),
// NOT use Offstage to wrap LinearProgressIndicator
if (isInProgress) const LinearProgressIndicator(),
],
),
actions: [
dialogButton("Cancel", onPressed: close, isOutline: true),
dialogButton("OK", onPressed: submit),
],
onSubmit: submit,
onCancel: close,
);
});
}
void renameDialog(
{required String oldName,
FormFieldValidator<String>? validator,
@@ -2002,15 +2121,20 @@ void showWindowsSessionsDialog(
return CustomAlertDialog(
title: null,
content: msgboxContent(type, title, text),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
msgboxContent(type, title, text).marginOnly(bottom: 12),
ComboBox(
keys: sids,
values: names,
initialKey: selectedUserValue,
onChanged: (value) {
selectedUserValue = value;
}),
],
),
actions: [
ComboBox(
keys: sids,
values: names,
initialKey: selectedUserValue,
onChanged: (value) {
selectedUserValue = value;
}),
dialogButton('Connect', onPressed: submit, isOutline: false),
],
);

View File

@@ -1,6 +1,7 @@
import 'dart:async';
import 'package:flutter/gestures.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_hbb/common/widgets/remote_input.dart';
enum GestureState {
none,
@@ -96,6 +97,12 @@ class CustomTouchGestureRecognizer extends ScaleGestureRecognizer {
if (onTwoFingerScaleEnd != null) {
onTwoFingerScaleEnd!(d);
}
if (isSpecialHoldDragActive) {
// If we are in special drag mode, we need to reset the state.
// Otherwise, the next `onTwoFingerScaleUpdate()` will handle a wrong `focalPoint`.
_currentState = GestureState.none;
return;
}
break;
case GestureState.threeFingerVerticalDrag:
debugPrint("ThreeFingerState.vertical onEnd");

View File

@@ -166,10 +166,13 @@ class _WidgetOPState extends State<WidgetOP> {
final String stateMsg = resultMap['state_msg'];
String failedMsg = resultMap['failed_msg'];
final String? url = resultMap['url'];
final bool urlLaunched = (resultMap['url_launched'] as bool?) ?? false;
final authBody = resultMap['auth_body'];
if (_stateMsg != stateMsg || _failedMsg != failedMsg) {
if (_url.isEmpty && url != null && url.isNotEmpty) {
launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication);
if (!urlLaunched) {
launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication);
}
_url = url;
}
if (authBody != null) {
@@ -455,10 +458,14 @@ Future<bool?> loginDialog() async {
resp.user, resp.secret, isEmailVerification);
} else {
setState(() => isInProgress = false);
// Workaround for web, close the dialog first, then show the verification code dialog.
// Otherwise, the text field will keep selecting the text and we can't input the code.
// Not sure why this happens.
if (isWeb && close != null) close(null);
final res = await verificationCodeDialog(
resp.user, resp.secret, isEmailVerification);
if (res == true) {
if (close != null) close(false);
if (!isWeb && close != null) close(false);
return;
}
}

View File

@@ -20,8 +20,11 @@ class MyGroup extends StatefulWidget {
}
class _MyGroupState extends State<MyGroup> {
RxString get selectedUser => gFFI.groupModel.selectedUser;
RxString get searchUserText => gFFI.groupModel.searchUserText;
RxBool get isSelectedDeviceGroup => gFFI.groupModel.isSelectedDeviceGroup;
RxString get selectedAccessibleItemName =>
gFFI.groupModel.selectedAccessibleItemName;
RxString get searchAccessibleItemNameText =>
gFFI.groupModel.searchAccessibleItemNameText;
static TextEditingController searchUserController = TextEditingController();
@override
@@ -72,7 +75,7 @@ class _MyGroupState extends State<MyGroup> {
child: Container(
width: double.infinity,
height: double.infinity,
child: _buildUserContacts(),
child: _buildLeftList(),
),
)
],
@@ -105,7 +108,7 @@ class _MyGroupState extends State<MyGroup> {
_buildLeftHeader(),
Container(
width: double.infinity,
child: _buildUserContacts(),
child: _buildLeftList(),
)
],
),
@@ -130,7 +133,8 @@ class _MyGroupState extends State<MyGroup> {
child: TextField(
controller: searchUserController,
onChanged: (value) {
searchUserText.value = value;
searchAccessibleItemNameText.value = value;
selectedAccessibleItemName.value = '';
},
textAlignVertical: TextAlignVertical.center,
style: TextStyle(fontSize: fontSize),
@@ -150,20 +154,30 @@ class _MyGroupState extends State<MyGroup> {
);
}
Widget _buildUserContacts() {
Widget _buildLeftList() {
return Obx(() {
final items = gFFI.groupModel.users.where((p0) {
if (searchUserText.isNotEmpty) {
final userItems = gFFI.groupModel.users.where((p0) {
if (searchAccessibleItemNameText.isNotEmpty) {
return p0.name
.toLowerCase()
.contains(searchUserText.value.toLowerCase());
.contains(searchAccessibleItemNameText.value.toLowerCase());
}
return true;
}).toList();
final deviceGroupItems = gFFI.groupModel.deviceGroups.where((p0) {
if (searchAccessibleItemNameText.isNotEmpty) {
return p0.name
.toLowerCase()
.contains(searchAccessibleItemNameText.value.toLowerCase());
}
return true;
}).toList();
listView(bool isPortrait) => ListView.builder(
shrinkWrap: isPortrait,
itemCount: items.length,
itemBuilder: (context, index) => _buildUserItem(items[index]));
itemCount: deviceGroupItems.length + userItems.length,
itemBuilder: (context, index) => index < deviceGroupItems.length
? _buildDeviceGroupItem(deviceGroupItems[index])
: _buildUserItem(userItems[index - deviceGroupItems.length]));
var maxHeight = max(MediaQuery.of(context).size.height / 6, 100.0);
return Obx(() => stateGlobal.isPortrait.isFalse
? listView(false)
@@ -174,14 +188,16 @@ class _MyGroupState extends State<MyGroup> {
Widget _buildUserItem(UserPayload user) {
final username = user.name;
return InkWell(onTap: () {
if (selectedUser.value != username) {
selectedUser.value = username;
isSelectedDeviceGroup.value = false;
if (selectedAccessibleItemName.value != username) {
selectedAccessibleItemName.value = username;
} else {
selectedUser.value = '';
selectedAccessibleItemName.value = '';
}
}, child: Obx(
() {
bool selected = selectedUser.value == username;
bool selected = !isSelectedDeviceGroup.value &&
selectedAccessibleItemName.value == username;
final isMe = username == gFFI.userModel.userName.value;
final colorMe = MyTheme.color(context).me!;
return Container(
@@ -238,4 +254,43 @@ class _MyGroupState extends State<MyGroup> {
},
)).marginSymmetric(horizontal: 12).marginOnly(bottom: 6);
}
Widget _buildDeviceGroupItem(DeviceGroupPayload deviceGroup) {
final name = deviceGroup.name;
return InkWell(onTap: () {
isSelectedDeviceGroup.value = true;
if (selectedAccessibleItemName.value != name) {
selectedAccessibleItemName.value = name;
} else {
selectedAccessibleItemName.value = '';
}
}, child: Obx(
() {
bool selected = isSelectedDeviceGroup.value &&
selectedAccessibleItemName.value == name;
return Container(
decoration: BoxDecoration(
color: selected ? MyTheme.color(context).highlight : null,
border: Border(
bottom: BorderSide(
width: 0.7,
color: Theme.of(context).dividerColor.withOpacity(0.1))),
),
child: Container(
child: Row(
children: [
Container(
width: 20,
height: 20,
child: Icon(IconFont.deviceGroupOutline,
color: MyTheme.accent, size: 19),
).marginOnly(right: 4),
Expanded(child: Text(name)),
],
).paddingSymmetric(vertical: 4),
),
);
},
)).marginSymmetric(horizontal: 12).marginOnly(bottom: 6);
}
}

View File

@@ -127,6 +127,10 @@ class _PeerCardState extends State<_PeerCard>
);
}
bool _showNote(Peer peer) {
return peerTabShowNote(widget.tab) && peer.note.isNotEmpty;
}
makeChild(bool isPortrait, Peer peer) {
final name = hideUsernameOnCard == true
? peer.hostname
@@ -134,6 +138,8 @@ class _PeerCardState extends State<_PeerCard>
final greyStyle = TextStyle(
fontSize: 11,
color: Theme.of(context).textTheme.titleLarge?.color?.withOpacity(0.6));
final showNote = _showNote(peer);
return Row(
mainAxisSize: MainAxisSize.max,
children: [
@@ -185,14 +191,44 @@ class _PeerCardState extends State<_PeerCard>
style: Theme.of(context).textTheme.titleSmall,
)),
]).marginOnly(top: isPortrait ? 0 : 2),
Align(
alignment: Alignment.centerLeft,
child: Text(
name,
style: isPortrait ? null : greyStyle,
textAlign: TextAlign.start,
overflow: TextOverflow.ellipsis,
),
Row(
children: [
Flexible(
child: Tooltip(
message: name,
waitDuration: const Duration(seconds: 1),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
name,
style: isPortrait ? null : greyStyle,
textAlign: TextAlign.start,
overflow: TextOverflow.ellipsis,
),
),
),
),
if (showNote)
Expanded(
child: Tooltip(
message: peer.note,
waitDuration: const Duration(seconds: 1),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
peer.note,
style: isPortrait ? null : greyStyle,
textAlign: TextAlign.start,
overflow: TextOverflow.ellipsis,
).marginOnly(
left: peerCardUiType.value ==
PeerUiType.list
? 32
: 4),
),
),
)
],
),
],
).marginOnly(top: 2),
@@ -278,7 +314,7 @@ class _PeerCardState extends State<_PeerCard>
padding: const EdgeInsets.all(6),
child:
getPlatformImage(peer.platform, size: 60),
).marginOnly(top: 4),
),
Row(
children: [
Expanded(
@@ -297,8 +333,26 @@ class _PeerCardState extends State<_PeerCard>
),
],
),
if (_showNote(peer))
Row(
children: [
Expanded(
child: Tooltip(
message: peer.note,
waitDuration: const Duration(seconds: 1),
child: Text(
peer.note,
style: const TextStyle(
color: Colors.white38,
fontSize: 10),
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
),
))
],
),
],
).paddingAll(4.0),
).paddingOnly(top: 4.0, left: 4.0, right: 4.0),
),
],
),
@@ -488,8 +542,11 @@ abstract class BasePeerCard extends StatelessWidget {
BuildContext context,
String title, {
bool isFileTransfer = false,
bool isViewCamera = false,
bool isTcpTunneling = false,
bool isRDP = false,
bool isTerminal = false,
bool isTerminalRunAsAdmin = false,
}) {
return MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Text(
@@ -497,13 +554,18 @@ abstract class BasePeerCard extends StatelessWidget {
style: style,
),
proc: () {
if (isTerminalRunAsAdmin) {
setEnvTerminalAdmin();
}
connectInPeerTab(
context,
peer,
tab,
isFileTransfer: isFileTransfer,
isViewCamera: isViewCamera,
isTcpTunneling: isTcpTunneling,
isRDP: isRDP,
isTerminal: isTerminal || isTerminalRunAsAdmin,
);
},
padding: menuPadding,
@@ -530,6 +592,33 @@ abstract class BasePeerCard extends StatelessWidget {
);
}
@protected
MenuEntryBase<String> _viewCameraAction(BuildContext context) {
return _connectCommonAction(
context,
translate('View camera'),
isViewCamera: true,
);
}
@protected
MenuEntryBase<String> _terminalAction(BuildContext context) {
return _connectCommonAction(
context,
'${translate('Terminal')} (beta)',
isTerminal: true,
);
}
@protected
MenuEntryBase<String> _terminalRunAsAdminAction(BuildContext context) {
return _connectCommonAction(
context,
'${translate('Terminal (Run as administrator)')} (beta)',
isTerminalRunAsAdmin: true,
);
}
@protected
MenuEntryBase<String> _tcpTunnelingAction(BuildContext context) {
return _connectCommonAction(
@@ -716,18 +805,18 @@ abstract class BasePeerCard extends StatelessWidget {
switch (tab) {
case PeerTabIndex.recent:
await bind.mainRemovePeer(id: id);
await bind.mainLoadRecentPeers();
bind.mainLoadRecentPeers();
break;
case PeerTabIndex.fav:
final favs = (await bind.mainGetFav()).toList();
if (favs.remove(id)) {
await bind.mainStoreFav(favs: favs);
await bind.mainLoadFavPeers();
bind.mainLoadFavPeers();
}
break;
case PeerTabIndex.lan:
await bind.mainRemoveDiscovered(id: id);
await bind.mainLoadLanPeers();
bind.mainLoadLanPeers();
break;
case PeerTabIndex.ab:
await gFFI.abModel.deletePeers([id]);
@@ -880,8 +969,14 @@ class RecentPeerCard extends BasePeerCard {
final List<MenuEntryBase<String>> menuItems = [
_connectAction(context),
_transferFileAction(context),
_viewCameraAction(context),
_terminalAction(context),
];
if (peer.platform == kPeerPlatformWindows) {
menuItems.add(_terminalRunAsAdminAction(context));
}
final List favs = (await bind.mainGetFav()).toList();
if (isDesktop && peer.platform != kPeerPlatformAndroid) {
@@ -939,7 +1034,14 @@ class FavoritePeerCard extends BasePeerCard {
final List<MenuEntryBase<String>> menuItems = [
_connectAction(context),
_transferFileAction(context),
_viewCameraAction(context),
_terminalAction(context),
];
if (peer.platform == kPeerPlatformWindows) {
menuItems.add(_terminalRunAsAdminAction(context));
}
if (isDesktop && peer.platform != kPeerPlatformAndroid) {
menuItems.add(_tcpTunnelingAction(context));
}
@@ -992,8 +1094,14 @@ class DiscoveredPeerCard extends BasePeerCard {
final List<MenuEntryBase<String>> menuItems = [
_connectAction(context),
_transferFileAction(context),
_viewCameraAction(context),
_terminalAction(context),
];
if (peer.platform == kPeerPlatformWindows) {
menuItems.add(_terminalRunAsAdminAction(context));
}
final List favs = (await bind.mainGetFav()).toList();
if (isDesktop && peer.platform != kPeerPlatformAndroid) {
@@ -1045,12 +1153,21 @@ class AddressBookPeerCard extends BasePeerCard {
final List<MenuEntryBase<String>> menuItems = [
_connectAction(context),
_transferFileAction(context),
_viewCameraAction(context),
_terminalAction(context),
];
if (peer.platform == kPeerPlatformWindows) {
menuItems.add(_terminalRunAsAdminAction(context));
}
if (isDesktop && peer.platform != kPeerPlatformAndroid) {
menuItems.add(_tcpTunnelingAction(context));
}
// menuItems.add(await _openNewConnInOptAction(peer.id));
// menuItems.add(await _forceAlwaysRelayAction(peer.id));
if (!isWeb) {
menuItems.add(await _forceAlwaysRelayAction(peer.id));
}
if (isWindows && peer.platform == kPeerPlatformWindows) {
menuItems.add(_rdpAction(context, peer.id));
}
@@ -1071,6 +1188,7 @@ class AddressBookPeerCard extends BasePeerCard {
if (gFFI.abModel.currentAbTags.isNotEmpty) {
menuItems.add(_editTagAction(peer.id));
}
menuItems.add(_editNoteAction(peer.id));
}
final addressbooks = gFFI.abModel.addressBooksCanWrite();
if (gFFI.peerTabModel.currentTab == PeerTabIndex.ab.index) {
@@ -1110,6 +1228,21 @@ class AddressBookPeerCard extends BasePeerCard {
);
}
@protected
MenuEntryBase<String> _editNoteAction(String id) {
return MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Text(
translate('Edit note'),
style: style,
),
proc: () {
editAbPeerNoteDialog(id);
},
padding: super.menuPadding,
dismissOnClicked: true,
);
}
@protected
@override
Future<String> _getAlias(String id) async =>
@@ -1177,12 +1310,21 @@ class MyGroupPeerCard extends BasePeerCard {
final List<MenuEntryBase<String>> menuItems = [
_connectAction(context),
_transferFileAction(context),
_viewCameraAction(context),
_terminalAction(context),
];
if (peer.platform == kPeerPlatformWindows) {
menuItems.add(_terminalRunAsAdminAction(context));
}
if (isDesktop && peer.platform != kPeerPlatformAndroid) {
menuItems.add(_tcpTunnelingAction(context));
}
// menuItems.add(await _openNewConnInOptAction(peer.id));
// menuItems.add(await _forceAlwaysRelayAction(peer.id));
if (!isWeb) {
menuItems.add(await _forceAlwaysRelayAction(peer.id));
}
if (isWindows && peer.platform == kPeerPlatformWindows) {
menuItems.add(_rdpAction(context, peer.id));
}
@@ -1398,8 +1540,10 @@ class TagPainter extends CustomPainter {
void connectInPeerTab(BuildContext context, Peer peer, PeerTabIndex tab,
{bool isFileTransfer = false,
bool isViewCamera = false,
bool isTcpTunneling = false,
bool isRDP = false}) async {
bool isRDP = false,
bool isTerminal = false}) async {
var password = '';
bool isSharedPassword = false;
if (tab == PeerTabIndex.ab) {
@@ -1417,12 +1561,21 @@ void connectInPeerTab(BuildContext context, Peer peer, PeerTabIndex tab,
password = peer.password;
isSharedPassword = true;
}
if (password.isEmpty) {
final abPassword = gFFI.abModel.getdefaultSharedPassword();
if (abPassword != null) {
password = abPassword;
isSharedPassword = true;
}
}
}
}
connect(context, peer.id,
password: password,
isSharedPassword: isSharedPassword,
isFileTransfer: isFileTransfer,
isTerminal: isTerminal,
isViewCamera: isViewCamera,
isTcpTunneling: isTcpTunneling,
isRDP: isRDP);
}

View File

@@ -33,8 +33,8 @@ class PeerTabPage extends StatefulWidget {
class _TabEntry {
final Widget widget;
final Function({dynamic hint}) load;
_TabEntry(this.widget, this.load);
final Function({dynamic hint})? load;
_TabEntry(this.widget, [this.load]);
}
EdgeInsets? _menuPadding() {
@@ -44,21 +44,15 @@ EdgeInsets? _menuPadding() {
class _PeerTabPageState extends State<PeerTabPage>
with SingleTickerProviderStateMixin {
final List<_TabEntry> entries = [
_TabEntry(
RecentPeersView(
menuPadding: _menuPadding(),
),
bind.mainLoadRecentPeers),
_TabEntry(
FavoritePeersView(
menuPadding: _menuPadding(),
),
bind.mainLoadFavPeers),
_TabEntry(
DiscoveredPeersView(
menuPadding: _menuPadding(),
),
bind.mainDiscover),
_TabEntry(RecentPeersView(
menuPadding: _menuPadding(),
)),
_TabEntry(FavoritePeersView(
menuPadding: _menuPadding(),
)),
_TabEntry(DiscoveredPeersView(
menuPadding: _menuPadding(),
)),
_TabEntry(
AddressBook(
menuPadding: _menuPadding(),
@@ -100,7 +94,7 @@ class _PeerTabPageState extends State<PeerTabPage>
gFFI.peerTabModel.setCurrentTabCachedPeers([]);
}
gFFI.peerTabModel.setCurrentTab(tabIndex);
entries[tabIndex].load(hint: false);
entries[tabIndex].load?.call(hint: false);
}
}
@@ -225,7 +219,7 @@ class _PeerTabPageState extends State<PeerTabPage>
child: RefreshWidget(
onPressed: () {
if (gFFI.peerTabModel.currentTab < entries.length) {
entries[gFFI.peerTabModel.currentTab].load();
entries[gFFI.peerTabModel.currentTab].load?.call();
}
},
spinning: loading,
@@ -404,7 +398,7 @@ class _PeerTabPageState extends State<PeerTabPage>
for (var p in peers) {
await bind.mainRemovePeer(id: p.id);
}
await bind.mainLoadRecentPeers();
bind.mainLoadRecentPeers();
break;
case 1:
final favs = (await bind.mainGetFav()).toList();
@@ -412,13 +406,13 @@ class _PeerTabPageState extends State<PeerTabPage>
favs.remove(p.id);
}).toList();
await bind.mainStoreFav(favs: favs);
await bind.mainLoadFavPeers();
bind.mainLoadFavPeers();
break;
case 2:
for (var p in peers) {
await bind.mainRemoveDiscovered(id: p.id);
}
await bind.mainLoadLanPeers();
bind.mainLoadLanPeers();
break;
case 3:
await gFFI.abModel.deletePeers(peers.map((p) => p.id).toList());

View File

@@ -25,13 +25,13 @@ class PeerSortType {
static const String remoteId = 'Remote ID';
static const String remoteHost = 'Remote Host';
static const String username = 'Username';
// static const String status = 'Status';
static const String status = 'Status';
static List<String> values = [
PeerSortType.remoteId,
PeerSortType.remoteHost,
PeerSortType.username,
// PeerSortType.status
PeerSortType.status
];
}
@@ -71,10 +71,12 @@ class _PeersView extends StatefulWidget {
final Peers peers;
final PeerFilter? peerFilter;
final PeerCardBuilder peerCardBuilder;
final PeerTabIndex peerTabIndex;
const _PeersView(
{required this.peers,
required this.peerCardBuilder,
required this.peerTabIndex,
this.peerFilter,
Key? key})
: super(key: key);
@@ -384,9 +386,9 @@ class _PeersViewState extends State<_PeersView>
peers.sort((p1, p2) =>
p1.username.toLowerCase().compareTo(p2.username.toLowerCase()));
break;
// case PeerSortType.status:
// peers.sort((p1, p2) => p1.online ? -1 : 1);
// break;
case PeerSortType.status:
peers.sort((p1, p2) => p1.online ? -1 : 1);
break;
}
}
@@ -395,8 +397,8 @@ class _PeersViewState extends State<_PeersView>
return peers;
}
searchText = searchText.toLowerCase();
final matches =
await Future.wait(peers.map((peer) => matchPeer(searchText, peer)));
final matches = await Future.wait(
peers.map((peer) => matchPeer(searchText, peer, widget.peerTabIndex)));
final filteredList = List<Peer>.empty(growable: true);
for (var i = 0; i < peers.length; i++) {
if (matches[i]) {
@@ -441,7 +443,10 @@ abstract class BasePeersView extends StatelessWidget {
break;
}
return _PeersView(
peers: peers, peerFilter: peerFilter, peerCardBuilder: peerCardBuilder);
peers: peers,
peerFilter: peerFilter,
peerCardBuilder: peerCardBuilder,
peerTabIndex: peerTabIndex);
}
}
@@ -501,6 +506,7 @@ class DiscoveredPeersView extends BasePeersView {
Widget build(BuildContext context) {
final widget = super.build(context);
bind.mainLoadLanPeers();
bind.mainDiscover();
return widget;
}
}
@@ -562,14 +568,26 @@ class MyGroupPeerView extends BasePeersView {
);
static bool filter(Peer peer) {
if (gFFI.groupModel.searchUserText.isNotEmpty) {
if (!peer.loginName.contains(gFFI.groupModel.searchUserText)) {
final model = gFFI.groupModel;
if (model.searchAccessibleItemNameText.isNotEmpty) {
final text = model.searchAccessibleItemNameText.value;
final searchPeersOfUser = peer.loginName.contains(text) &&
model.users.any((user) => user.name == peer.loginName);
final searchPeersOfDeviceGroup = peer.device_group_name.contains(text) &&
model.deviceGroups.any((g) => g.name == peer.device_group_name);
if (!searchPeersOfUser && !searchPeersOfDeviceGroup) {
return false;
}
}
if (gFFI.groupModel.selectedUser.isNotEmpty) {
if (gFFI.groupModel.selectedUser.value != peer.loginName) {
return false;
if (model.selectedAccessibleItemName.isNotEmpty) {
if (model.isSelectedDeviceGroup.value) {
if (model.selectedAccessibleItemName.value != peer.device_group_name) {
return false;
}
} else {
if (model.selectedAccessibleItemName.value != peer.loginName) {
return false;
}
}
}
return true;

View File

@@ -1,4 +1,5 @@
import 'dart:convert';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@@ -50,16 +51,24 @@ class RawKeyFocusScope extends StatelessWidget {
}
}
// For virtual mouse when using the mouse mode on mobile.
// Special hold-drag mode: one finger holds a button (left/right button), another finger pans.
// This flag is to override the scale gesture to a pan gesture.
bool isSpecialHoldDragActive = false;
// Cache the last focal point to calculate deltas in special hold-drag mode.
Offset _lastSpecialHoldDragFocalPoint = Offset.zero;
class RawTouchGestureDetectorRegion extends StatefulWidget {
final Widget child;
final FFI ffi;
final bool isCamera;
late final InputModel inputModel = ffi.inputModel;
late final FfiModel ffiModel = ffi.ffiModel;
RawTouchGestureDetectorRegion({
required this.child,
required this.ffi,
this.isCamera = false,
});
@override
@@ -95,6 +104,10 @@ class _RawTouchGestureDetectorRegionState
bool _touchModePanStarted = false;
Offset _doubleFinerTapPosition = Offset.zero;
// For mouse mode, we need to block the events when the cursor is in a blocked area.
// So we need to cache the last tap down position.
Offset? _lastTapDownPositionForMouseMode;
FFI get ffi => widget.ffi;
FfiModel get ffiModel => widget.ffiModel;
InputModel get inputModel => widget.inputModel;
@@ -109,22 +122,36 @@ class _RawTouchGestureDetectorRegionState
);
}
bool isNotTouchBasedDevice() {
return !kTouchBasedDeviceKinds.contains(lastDeviceKind);
}
// Mobile, mouse mode.
// Check if should block the mouse tap event (`_lastTapDownPositionForMouseMode`).
bool shouldBlockMouseModeEvent() {
return _lastTapDownPositionForMouseMode != null &&
ffi.cursorModel.shouldBlock(_lastTapDownPositionForMouseMode!.dx,
_lastTapDownPositionForMouseMode!.dy);
}
onTapDown(TapDownDetails d) async {
lastDeviceKind = d.kind;
if (lastDeviceKind != PointerDeviceKind.touch) {
if (isNotTouchBasedDevice()) {
return;
}
if (handleTouch) {
_lastPosOfDoubleTapDown = d.localPosition;
// Desktop or mobile "Touch mode"
_lastTapDownDetails = d;
} else {
_lastTapDownPositionForMouseMode = d.localPosition;
}
}
onTapUp(TapUpDetails d) async {
final TapDownDetails? lastTapDownDetails = _lastTapDownDetails;
_lastTapDownDetails = null;
if (lastDeviceKind != PointerDeviceKind.touch) {
if (isNotTouchBasedDevice()) {
return;
}
if (handleTouch) {
@@ -140,10 +167,15 @@ class _RawTouchGestureDetectorRegionState
}
onTap() async {
if (lastDeviceKind != PointerDeviceKind.touch) {
if (isNotTouchBasedDevice()) {
return;
}
if (!handleTouch) {
// Cannot use `_lastTapDownDetails` because Flutter calls `onTapUp` before `onTap`, clearing the cached details.
// Using `_lastTapDownPositionForMouseMode` instead.
if (shouldBlockMouseModeEvent()) {
return;
}
// Mobile, "Mouse mode"
await inputModel.tap(MouseButtons.left);
}
@@ -151,17 +183,19 @@ class _RawTouchGestureDetectorRegionState
onDoubleTapDown(TapDownDetails d) async {
lastDeviceKind = d.kind;
if (lastDeviceKind != PointerDeviceKind.touch) {
if (isNotTouchBasedDevice()) {
return;
}
if (handleTouch) {
_lastPosOfDoubleTapDown = d.localPosition;
await ffi.cursorModel.move(d.localPosition.dx, d.localPosition.dy);
} else {
_lastTapDownPositionForMouseMode = d.localPosition;
}
}
onDoubleTap() async {
if (lastDeviceKind != PointerDeviceKind.touch) {
if (isNotTouchBasedDevice()) {
return;
}
if (ffiModel.touchMode && ffi.cursorModel.lastIsBlocked) {
@@ -171,13 +205,19 @@ class _RawTouchGestureDetectorRegionState
!ffi.cursorModel.isInRemoteRect(_lastPosOfDoubleTapDown)) {
return;
}
// Check if the position is in a blocked area when using the mouse mode.
if (!handleTouch) {
if (shouldBlockMouseModeEvent()) {
return;
}
}
await inputModel.tap(MouseButtons.left);
await inputModel.tap(MouseButtons.left);
}
onLongPressDown(LongPressDownDetails d) async {
lastDeviceKind = d.kind;
if (lastDeviceKind != PointerDeviceKind.touch) {
if (isNotTouchBasedDevice()) {
return;
}
if (handleTouch) {
@@ -187,11 +227,18 @@ class _RawTouchGestureDetectorRegionState
return;
}
_cacheLongPressPositionTs = DateTime.now().millisecondsSinceEpoch;
if (ffiModel.isPeerMobile) {
await ffi.cursorModel
.move(_cacheLongPressPosition.dx, _cacheLongPressPosition.dy);
await inputModel.tapDown(MouseButtons.left);
}
} else {
_lastTapDownPositionForMouseMode = d.localPosition;
}
}
onLongPressUp() async {
if (lastDeviceKind != PointerDeviceKind.touch) {
if (isNotTouchBasedDevice()) {
return;
}
if (handleTouch) {
@@ -201,24 +248,44 @@ class _RawTouchGestureDetectorRegionState
// for mobiles
onLongPress() async {
if (lastDeviceKind != PointerDeviceKind.touch) {
if (isNotTouchBasedDevice()) {
return;
}
if (!ffi.ffiModel.isPeerMobile) {
if (handleTouch) {
final isMoved = await ffi.cursorModel
.move(_cacheLongPressPosition.dx, _cacheLongPressPosition.dy);
if (!isMoved) {
return;
}
} else {
if (shouldBlockMouseModeEvent()) {
return;
}
}
await inputModel.tap(MouseButtons.right);
} else {
// It's better to send a message to tell the controlled device that the long press event is triggered.
// We're now using a `TimerTask` in `InputService.kt` to decide whether to trigger the long press event.
// It's not accurate and it's better to use the same detection logic in the controlling side.
}
}
onLongPressMoveUpdate(LongPressMoveUpdateDetails d) async {
if (!ffiModel.isPeerMobile || isNotTouchBasedDevice()) {
return;
}
if (handleTouch) {
final isMoved = await ffi.cursorModel
.move(_cacheLongPressPosition.dx, _cacheLongPressPosition.dy);
if (!isMoved) {
if (!ffi.cursorModel.isInRemoteRect(d.localPosition)) {
return;
}
}
if (!ffi.ffiModel.isPeerMobile) {
await inputModel.tap(MouseButtons.right);
await ffi.cursorModel.move(d.localPosition.dx, d.localPosition.dy);
}
}
onDoubleFinerTapDown(TapDownDetails d) async {
lastDeviceKind = d.kind;
if (lastDeviceKind != PointerDeviceKind.touch) {
if (isNotTouchBasedDevice()) {
return;
}
_doubleFinerTapPosition = d.localPosition;
@@ -227,7 +294,7 @@ class _RawTouchGestureDetectorRegionState
onDoubleFinerTap(TapDownDetails d) async {
lastDeviceKind = d.kind;
if (lastDeviceKind != PointerDeviceKind.touch) {
if (isNotTouchBasedDevice()) {
return;
}
@@ -243,25 +310,27 @@ class _RawTouchGestureDetectorRegionState
onHoldDragStart(DragStartDetails d) async {
lastDeviceKind = d.kind;
if (lastDeviceKind != PointerDeviceKind.touch) {
if (isNotTouchBasedDevice()) {
return;
}
if (!handleTouch) {
if (isSpecialHoldDragActive) return;
await inputModel.sendMouse('down', MouseButtons.left);
}
}
onHoldDragUpdate(DragUpdateDetails d) async {
if (lastDeviceKind != PointerDeviceKind.touch) {
if (isNotTouchBasedDevice()) {
return;
}
if (!handleTouch) {
if (isSpecialHoldDragActive) return;
await ffi.cursorModel.updatePan(d.delta, d.localPosition, handleTouch);
}
}
onHoldDragEnd(DragEndDetails d) async {
if (lastDeviceKind != PointerDeviceKind.touch) {
if (isNotTouchBasedDevice()) {
return;
}
if (!handleTouch) {
@@ -273,7 +342,7 @@ class _RawTouchGestureDetectorRegionState
final TapDownDetails? lastTapDownDetails = _lastTapDownDetails;
_lastTapDownDetails = null;
lastDeviceKind = d.kind ?? lastDeviceKind;
if (lastDeviceKind != PointerDeviceKind.touch) {
if (isNotTouchBasedDevice()) {
return;
}
if (handleTouch) {
@@ -319,7 +388,7 @@ class _RawTouchGestureDetectorRegionState
}
onOneFingerPanUpdate(DragUpdateDetails d) async {
if (lastDeviceKind != PointerDeviceKind.touch) {
if (isNotTouchBasedDevice()) {
return;
}
if (ffi.cursorModel.shouldBlock(d.localPosition.dx, d.localPosition.dy)) {
@@ -333,34 +402,49 @@ class _RawTouchGestureDetectorRegionState
onOneFingerPanEnd(DragEndDetails d) async {
_touchModePanStarted = false;
if (lastDeviceKind != PointerDeviceKind.touch) {
if (isNotTouchBasedDevice()) {
return;
}
if (isDesktop || isWebDesktop) {
ffi.cursorModel.clearRemoteWindowCoords();
}
if (handleTouch) {
await inputModel.sendMouse('up', MouseButtons.left);
await inputModel.sendMouse('up', MouseButtons.left);
}
}
// scale + pan event
onTwoFingerScaleStart(ScaleStartDetails d) {
_lastTapDownDetails = null;
if (lastDeviceKind != PointerDeviceKind.touch) {
if (isNotTouchBasedDevice()) {
return;
}
if (isSpecialHoldDragActive) {
// Initialize the last focal point to calculate deltas manually.
_lastSpecialHoldDragFocalPoint = d.focalPoint;
}
}
onTwoFingerScaleUpdate(ScaleUpdateDetails d) async {
if (lastDeviceKind != PointerDeviceKind.touch) {
if (isNotTouchBasedDevice()) {
return;
}
// If in special drag mode, perform a pan instead of a scale.
if (isSpecialHoldDragActive) {
// Calculate delta manually to avoid the jumpy behavior.
final delta = d.focalPoint - _lastSpecialHoldDragFocalPoint;
_lastSpecialHoldDragFocalPoint = d.focalPoint;
await ffi.cursorModel.updatePan(delta * 2.0, d.focalPoint, handleTouch);
return;
}
if ((isDesktop || isWebDesktop)) {
final scale = ((d.scale - _scale) * 1000).toInt();
_scale = d.scale;
if (scale != 0) {
if (widget.isCamera) return;
await bind.sessionSendPointer(
sessionId: sessionId,
msg: json.encode(
@@ -377,10 +461,11 @@ class _RawTouchGestureDetectorRegionState
}
onTwoFingerScaleEnd(ScaleEndDetails d) async {
if (lastDeviceKind != PointerDeviceKind.touch) {
if (isNotTouchBasedDevice()) {
return;
}
if ((isDesktop || isWebDesktop)) {
if (widget.isCamera) return;
await bind.sessionSendPointer(
sessionId: sessionId,
msg: json.encode(
@@ -391,7 +476,9 @@ class _RawTouchGestureDetectorRegionState
// No idea why we need to set the view style to "" here.
// bind.sessionSetViewStyle(sessionId: sessionId, value: "");
}
await inputModel.sendMouse('up', MouseButtons.left);
if (!isSpecialHoldDragActive) {
await inputModel.sendMouse('up', MouseButtons.left);
}
}
get onHoldDragCancel => null;
@@ -432,7 +519,8 @@ class _RawTouchGestureDetectorRegionState
instance
..onLongPressDown = onLongPressDown
..onLongPressUp = onLongPressUp
..onLongPress = onLongPress;
..onLongPress = onLongPress
..onLongPressMoveUpdate = onLongPressMoveUpdate;
}),
// Customized
HoldTapMoveGestureRecognizer:
@@ -514,3 +602,46 @@ class RawPointerMouseRegion extends StatelessWidget {
);
}
}
class CameraRawPointerMouseRegion extends StatelessWidget {
final InputModel inputModel;
final Widget child;
final PointerEnterEventListener? onEnter;
final PointerExitEventListener? onExit;
final PointerDownEventListener? onPointerDown;
final PointerUpEventListener? onPointerUp;
CameraRawPointerMouseRegion({
this.onEnter,
this.onExit,
this.onPointerDown,
this.onPointerUp,
required this.inputModel,
required this.child,
});
@override
Widget build(BuildContext context) {
return Listener(
onPointerHover: (evt) {
final offset = evt.position;
double x = offset.dx;
double y = max(0.0, offset.dy);
inputModel.handlePointerDevicePos(
kPointerEventKindMouse, x, y, true, kMouseEventTypeDefault);
},
onPointerDown: (evt) {
onPointerDown?.call(evt);
},
onPointerUp: (evt) {
onPointerUp?.call(evt);
},
child: MouseRegion(
cursor: MouseCursor.defer,
onEnter: onEnter,
onExit: onExit,
child: child,
),
);
}
}

View File

@@ -230,7 +230,6 @@ List<(String, String)> otherDefaultSettings() {
('Disable clipboard', kOptionDisableClipboard),
('Lock after session end', kOptionLockAfterSessionEnd),
('Privacy mode', kOptionPrivacyMode),
if (isMobile) ('Touch mode', kOptionTouchMode),
('True color (4:4:4)', kOptionI444),
('Reverse mouse wheel', kKeyReverseMouseWheel),
('swap-left-right-mouse', kOptionSwapLeftRightMouse),
@@ -243,8 +242,99 @@ List<(String, String)> otherDefaultSettings() {
(
'Use all my displays for the remote session',
kKeyUseAllMyDisplaysForTheRemoteSession
)
),
('Keep terminal sessions on disconnect', kOptionTerminalPersistent),
];
return v;
}
class TrackpadSpeedWidget extends StatefulWidget {
final SimpleWrapper<int> value;
// If null, no debouncer will be applied.
final Function(int)? onDebouncer;
TrackpadSpeedWidget({Key? key, required this.value, this.onDebouncer});
@override
TrackpadSpeedWidgetState createState() => TrackpadSpeedWidgetState();
}
class TrackpadSpeedWidgetState extends State<TrackpadSpeedWidget> {
final TextEditingController _controller = TextEditingController();
late final Debouncer<int> debouncerSpeed;
set value(int v) => widget.value.value = v;
int get value => widget.value.value;
void updateValue(int newValue) {
setState(() {
value = newValue.clamp(kMinTrackpadSpeed, kMaxTrackpadSpeed);
// Scale the trackpad speed value to a percentage for display purposes.
_controller.text = value.toString();
if (widget.onDebouncer != null) {
debouncerSpeed.setValue(value);
}
});
}
@override
void initState() {
super.initState();
debouncerSpeed = Debouncer<int>(
Duration(milliseconds: 1000),
onChanged: widget.onDebouncer,
initialValue: widget.value.value,
);
}
@override
Widget build(BuildContext context) {
if (_controller.text.isEmpty) {
_controller.text = value.toString();
}
return Row(
children: [
Expanded(
flex: 3,
child: Slider(
value: value.toDouble(),
min: kMinTrackpadSpeed.toDouble(),
max: kMaxTrackpadSpeed.toDouble(),
divisions: ((kMaxTrackpadSpeed - kMinTrackpadSpeed) / 10).round(),
onChanged: (double v) => updateValue(v.round()),
),
),
Expanded(
flex: 1,
child: Row(
children: [
SizedBox(
width: 56,
child: TextField(
controller: _controller,
keyboardType: TextInputType.number,
textAlign: TextAlign.center,
onSubmitted: (text) {
int? v = int.tryParse(text);
if (v != null) {
updateValue(v);
}
},
style: const TextStyle(fontSize: 13),
decoration: InputDecoration(
contentPadding:
EdgeInsets.symmetric(vertical: 8.0, horizontal: 12.0),
),
),
).marginOnly(right: 8.0),
Text(
'%',
style: const TextStyle(fontSize: 15),
)
],
)),
],
);
}
}

View File

@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
@@ -15,7 +16,7 @@ bool isEditOsPassword = false;
class TTextMenu {
final Widget child;
final VoidCallback onPressed;
final VoidCallback? onPressed;
Widget? trailingIcon;
bool divider;
TTextMenu(
@@ -89,10 +90,13 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
final pi = ffiModel.pi;
final perms = ffiModel.permissions;
final sessionId = ffi.sessionId;
final isDefaultConn = ffi.connType == ConnType.defaultConn;
List<TTextMenu> v = [];
// elevation
if (perms['keyboard'] != false && ffi.elevationModel.showRequestMenu) {
if (isDefaultConn &&
perms['keyboard'] != false &&
ffi.elevationModel.showRequestMenu) {
v.add(
TTextMenu(
child: Text(translate('Request Elevation')),
@@ -101,7 +105,7 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
);
}
// osAccount / osPassword
if (perms['keyboard'] != false) {
if (isDefaultConn && perms['keyboard'] != false) {
v.add(
TTextMenu(
child: Row(children: [
@@ -130,7 +134,9 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
);
}
// paste
if (pi.platform != kPeerPlatformAndroid && perms['keyboard'] != false) {
if (isDefaultConn &&
pi.platform != kPeerPlatformAndroid &&
perms['keyboard'] != false) {
v.add(TTextMenu(
child: Text(translate('Send clipboard keystrokes')),
onPressed: () async {
@@ -142,43 +148,55 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
}));
}
// reset canvas
if (isMobile) {
if (isDefaultConn && isMobile) {
v.add(TTextMenu(
child: Text(translate('Reset canvas')),
onPressed: () => ffi.cursorModel.reset()));
}
// https://github.com/rustdesk/rustdesk/pull/9731
// Does not work for connection established by "accept".
connectWithToken(
{required bool isFileTransfer, required bool isTcpTunneling}) {
{bool isFileTransfer = false,
bool isViewCamera = false,
bool isTcpTunneling = false,
bool isTerminal = false}) {
final connToken = bind.sessionGetConnToken(sessionId: ffi.sessionId);
connect(context, id,
isFileTransfer: isFileTransfer,
isViewCamera: isViewCamera,
isTerminal: isTerminal,
isTcpTunneling: isTcpTunneling,
connToken: connToken);
}
// transferFile
if (isDesktop) {
if (isDefaultConn && isDesktop) {
v.add(
TTextMenu(
child: Text(translate('Transfer file')),
onPressed: () =>
connectWithToken(isFileTransfer: true, isTcpTunneling: false)),
onPressed: () => connectWithToken(isFileTransfer: true)),
);
v.add(
TTextMenu(
child: Text(translate('View camera')),
onPressed: () => connectWithToken(isViewCamera: true)),
);
v.add(
TTextMenu(
child: Text('${translate('Terminal')} (beta)'),
onPressed: () => connectWithToken(isTerminal: true)),
);
}
// tcpTunneling
if (isDesktop) {
v.add(
TTextMenu(
child: Text(translate('TCP tunneling')),
onPressed: () =>
connectWithToken(isFileTransfer: false, isTcpTunneling: true)),
onPressed: () => connectWithToken(isTcpTunneling: true)),
);
}
// note
if (bind
.sessionGetAuditServerSync(sessionId: sessionId, typ: "conn")
.isNotEmpty) {
if (isDefaultConn &&
bind
.sessionGetAuditServerSync(sessionId: sessionId, typ: "conn")
.isNotEmpty) {
v.add(
TTextMenu(
child: Text(translate('Note')),
@@ -186,11 +204,12 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
);
}
// divider
if (isDesktop || isWebDesktop) {
if (isDefaultConn && (isDesktop || isWebDesktop)) {
v.add(TTextMenu(child: Offstage(), onPressed: () {}, divider: true));
}
// ctrlAltDel
if (!ffiModel.viewOnly &&
if (isDefaultConn &&
!ffiModel.viewOnly &&
ffiModel.keyboard &&
(pi.platform == kPeerPlatformLinux || pi.sasEnabled)) {
v.add(
@@ -200,7 +219,8 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
);
}
// restart
if (perms['restart'] != false &&
if (isDefaultConn &&
perms['restart'] != false &&
(pi.platform == kPeerPlatformLinux ||
pi.platform == kPeerPlatformWindows ||
pi.platform == kPeerPlatformMacOS)) {
@@ -212,7 +232,7 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
);
}
// insertLock
if (!ffiModel.viewOnly && ffi.ffiModel.keyboard) {
if (isDefaultConn && !ffiModel.viewOnly && ffi.ffiModel.keyboard) {
v.add(
TTextMenu(
child: Text(translate('Insert Lock')),
@@ -220,7 +240,8 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
);
}
// blockUserInput
if (ffi.ffiModel.keyboard &&
if (isDefaultConn &&
ffi.ffiModel.keyboard &&
ffi.ffiModel.permissions['block_input'] != false &&
pi.platform == kPeerPlatformWindows) // privacy-mode != true ??
{
@@ -236,12 +257,13 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
}));
}
// switchSides
if (isDesktop &&
if (isDefaultConn &&
isDesktop &&
ffiModel.keyboard &&
pi.platform != kPeerPlatformAndroid &&
pi.platform != kPeerPlatformMacOS &&
versionCmp(pi.version, '1.2.0') >= 0 &&
bind.peerGetDefaultSessionsCount(id: id) == 1) {
bind.peerGetSessionsCount(id: id, connType: ffi.connType.index) == 1) {
v.add(TTextMenu(
child: Text(translate('Switch Sides')),
onPressed: () =>
@@ -275,6 +297,41 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
),
onPressed: () => ffi.recordingModel.toggle()));
}
// to-do:
// 1. Web desktop
// 2. Mobile, copy the image to the clipboard
if (isDesktop) {
final isScreenshotSupported = bind.sessionGetCommonSync(
sessionId: sessionId, key: 'is_screenshot_supported', param: '');
if ('true' == isScreenshotSupported) {
v.add(TTextMenu(
child: Text(ffi.ffiModel.timerScreenshot != null
? '${translate('Taking screenshot')} ...'
: translate('Take screenshot')),
onPressed: ffi.ffiModel.timerScreenshot != null
? null
: () {
if (pi.currentDisplay == kAllDisplayValue) {
msgBox(
sessionId,
'custom-nook-nocancel-hasclose-info',
'Take screenshot',
'screenshot-merged-screen-not-supported-tip',
'',
ffi.dialogManager);
} else {
bind.sessionTakeScreenshot(
sessionId: sessionId, display: pi.currentDisplay);
ffi.ffiModel.timerScreenshot =
Timer(Duration(seconds: 30), () {
ffi.ffiModel.timerScreenshot = null;
});
}
},
));
}
}
// fingerprint
if (!(isDesktop || isWebDesktop)) {
v.add(TTextMenu(
@@ -306,7 +363,13 @@ Future<List<TRadioMenu<String>>> toolbarViewStyle(
child: Text(translate('Scale adaptive')),
value: kRemoteViewStyleAdaptive,
groupValue: groupValue,
onChanged: onChanged)
onChanged: onChanged),
if (isDesktop || isWebDesktop)
TRadioMenu<String>(
child: Text(translate('Scale custom')),
value: kRemoteViewStyleCustom,
groupValue: groupValue,
onChanged: onChanged)
];
}
@@ -523,6 +586,7 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
final pi = ffiModel.pi;
final perms = ffiModel.permissions;
final sessionId = ffi.sessionId;
final isDefaultConn = ffi.connType == ConnType.defaultConn;
// show quality monitor
final option = 'show-quality-monitor';
@@ -535,7 +599,7 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
},
child: Text(translate('Show quality monitor'))));
// mute
if (perms['audio'] != false) {
if (isDefaultConn && perms['audio'] != false) {
final option = 'disable-audio';
final value =
bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option);
@@ -556,7 +620,8 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
final isSupportIfPeer_1_2_4 = versionCmp(pi.version, '1.2.4') >= 0 &&
bind.mainHasFileClipboard() &&
pi.platformAdditions.containsKey(kPlatformAdditionsHasFileClipboard);
if (ffiModel.keyboard &&
if (isDefaultConn &&
ffiModel.keyboard &&
perms['file'] != false &&
(isSupportIfPeer_1_2_3 || isSupportIfPeer_1_2_4)) {
final enabled = !ffiModel.viewOnly;
@@ -574,7 +639,7 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
child: Text(translate('Enable file copy and paste'))));
}
// disable clipboard
if (ffiModel.keyboard && perms['clipboard'] != false) {
if (isDefaultConn && ffiModel.keyboard && perms['clipboard'] != false) {
final enabled = !ffiModel.viewOnly;
final option = 'disable-clipboard';
var value =
@@ -591,7 +656,7 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
child: Text(translate('Disable clipboard'))));
}
// lock after session end
if (ffiModel.keyboard && !ffiModel.isPeerAndroid) {
if (isDefaultConn && ffiModel.keyboard && !ffiModel.isPeerAndroid) {
final enabled = !ffiModel.viewOnly;
final option = 'lock-after-session-end';
final value =
@@ -656,12 +721,12 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
child: Text(translate('True color (4:4:4)'))));
}
if (isMobile) {
if (isDefaultConn && isMobile) {
v.addAll(toolbarKeyboardToggles(ffi));
}
// view mode (mobile only, desktop is in keyboard menu)
if (isMobile && versionCmp(pi.version, '1.2.0') >= 0) {
if (isDefaultConn && isMobile && versionCmp(pi.version, '1.2.0') >= 0) {
v.add(TToggleMenu(
value: ffiModel.viewOnly,
onChanged: (value) async {

View File

@@ -1,3 +1,4 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hbb/common.dart';
import 'package:flutter_hbb/models/state_model.dart';
@@ -44,7 +45,9 @@ const String kAppTypeConnectionManager = "cm";
const String kAppTypeDesktopRemote = "remote";
const String kAppTypeDesktopFileTransfer = "file transfer";
const String kAppTypeDesktopViewCamera = "view camera";
const String kAppTypeDesktopPortForward = "port forward";
const String kAppTypeDesktopTerminal = "terminal";
const String kWindowMainWindowOnTop = "main_window_on_top";
const String kWindowGetWindowInfo = "get_window_info";
@@ -58,7 +61,10 @@ const String kWindowConnect = "connect";
const String kWindowEventNewRemoteDesktop = "new_remote_desktop";
const String kWindowEventNewFileTransfer = "new_file_transfer";
const String kWindowEventNewViewCamera = "new_view_camera";
const String kWindowEventNewPortForward = "new_port_forward";
const String kWindowEventNewTerminal = "new_terminal";
const String kWindowEventRestoreTerminalSessions = "restore_terminal_sessions";
const String kWindowEventActiveSession = "active_session";
const String kWindowEventActiveDisplaySession = "active_display_session";
const String kWindowEventGetRemoteList = "get_remote_list";
@@ -75,6 +81,7 @@ const String kOptionScrollStyle = "scroll_style";
const String kOptionImageQuality = "image_quality";
const String kOptionOpenNewConnInTabs = "enable-open-new-connections-in-tabs";
const String kOptionTextureRender = "use-texture-render";
const String kOptionD3DRender = "allow-d3d-render";
const String kOptionOpenInTabs = "allow-open-in-tabs";
const String kOptionOpenInWindows = "allow-open-in-windows";
const String kOptionForceAlwaysRelay = "force-always-relay";
@@ -94,9 +101,13 @@ const String kOptionVideoSaveDirectory = "video-save-directory";
const String kOptionAccessMode = "access-mode";
const String kOptionEnableKeyboard = "enable-keyboard";
// "Settings -> Security -> Permissions"
const String kOptionEnableRemotePrinter = "enable-remote-printer";
const String kOptionEnableClipboard = "enable-clipboard";
const String kOptionEnableFileTransfer = "enable-file-transfer";
const String kOptionEnableAudio = "enable-audio";
const String kOptionEnableCamera = "enable-camera";
const String kOptionEnableTerminal = "enable-terminal";
const String kOptionTerminalPersistent = "terminal-persistent";
const String kOptionEnableTunnel = "enable-tunnel";
const String kOptionEnableRemoteRestart = "enable-remote-restart";
const String kOptionEnableBlockInput = "enable-block-input";
@@ -104,6 +115,8 @@ const String kOptionAllowRemoteConfigModification =
"allow-remote-config-modification";
const String kOptionVerificationMethod = "verification-method";
const String kOptionApproveMode = "approve-mode";
const String kOptionAllowNumericOneTimePassword =
"allow-numeric-one-time-password";
const String kOptionCollapseToolbar = "collapse_toolbar";
const String kOptionShowRemoteCursor = "show_remote_cursor";
const String kOptionFollowRemoteCursor = "follow_remote_cursor";
@@ -133,16 +146,27 @@ const String kOptionCurrentAbName = "current-ab-name";
const String kOptionEnableConfirmClosingTabs = "enable-confirm-closing-tabs";
const String kOptionAllowAlwaysSoftwareRender = "allow-always-software-render";
const String kOptionEnableCheckUpdate = "enable-check-update";
const String kOptionAllowAutoUpdate = "allow-auto-update";
const String kOptionAllowLinuxHeadless = "allow-linux-headless";
const String kOptionAllowRemoveWallpaper = "allow-remove-wallpaper";
const String kOptionStopService = "stop-service";
const String kOptionDirectxCapture = "enable-directx-capture";
const String kOptionAllowRemoteCmModification = "allow-remote-cm-modification";
const String kOptionEnableUdpPunch = "enable-udp-punch";
const String kOptionEnableIpv6Punch = "enable-ipv6-punch";
const String kOptionEnableTrustedDevices = "enable-trusted-devices";
const String kOptionShowVirtualMouse = "show-virtual-mouse";
const String kOptionVirtualMouseScale = "virtual-mouse-scale";
const String kOptionShowVirtualJoystick = "show-virtual-joystick";
// network options
const String kOptionAllowWebSocket = "allow-websocket";
// buildin opitons
const String kOptionHideServerSetting = "hide-server-settings";
const String kOptionHideProxySetting = "hide-proxy-settings";
const String kOptionHideWebSocketSetting = "hide-websocket-settings";
const String kOptionHideRemotePrinterSetting = "hide-remote-printer-settings";
const String kOptionHideSecuritySetting = "hide-security-settings";
const String kOptionHideNetworkSetting = "hide-network-settings";
const String kOptionRemovePresetPasswordWarning =
@@ -151,6 +175,7 @@ const kHideUsernameOnCard = "hide-username-on-card";
const String kOptionHideHelpCards = "hide-help-cards";
const String kOptionToggleViewOnly = "view-only";
const String kOptionToggleShowMyCursor = "show-my-cursor";
const String kOptionDisableFloatingWindow = "disable-floating-window";
@@ -214,6 +239,21 @@ const double kDefaultQuality = 50;
const double kMaxQuality = 100;
const double kMaxMoreQuality = 2000;
// trackpad speed
const String kKeyTrackpadSpeed = 'trackpad-speed';
const int kMinTrackpadSpeed = 10;
const int kDefaultTrackpadSpeed = 100;
const int kMaxTrackpadSpeed = 1000;
// incomming (should be incoming) is kept, because change it will break the previous setting.
const String kKeyPrinterIncomingJobAction = 'printer-incomming-job-action';
const String kValuePrinterIncomingJobDismiss = 'dismiss';
const String kValuePrinterIncomingJobDefault = '';
const String kValuePrinterIncomingJobSelected = 'selected';
const String kKeyPrinterSelected = 'printer-selected-name';
const String kKeyPrinterSave = 'allow-printer-dialog-save';
const String kKeyPrinterAllowAutoPrint = 'allow-printer-auto-print';
double kNewWindowOffset = isWindows
? 56.0
: isLinux
@@ -248,7 +288,7 @@ const kFullScreenEdgeSize = 0.0;
const kMaximizeEdgeSize = 0.0;
// Do not use kWindowResizeEdgeSize directly. Use `windowResizeEdgeSize` in `common.dart` instead.
const kWindowResizeEdgeSize = 5.0;
const kWindowBorderWidth = 1.0;
final kWindowBorderWidth = isWindows ? 0.0 : 1.0;
const kDesktopMenuPadding = EdgeInsets.only(left: 12.0, right: 3.0);
const kFrameBorderRadius = 12.0;
const kFrameClipRRectBorderRadius = 12.0;
@@ -276,6 +316,10 @@ const kRemoteViewStyleOriginal = 'original';
/// [kRemoteViewStyleAdaptive] Show remote image scaling by ratio factor.
const kRemoteViewStyleAdaptive = 'adaptive';
/// [kRemoteViewStyleCustom] Show remote image at a user-defined scale percent.
const kRemoteViewStyleCustom = 'custom';
/// [kRemoteScrollStyleAuto] Scroll image auto by position.
const kRemoteScrollStyleAuto = 'scrollauto';
@@ -302,6 +346,21 @@ const kRemoteImageQualityCustom = 'custom';
const kIgnoreDpi = true;
const Set<PointerDeviceKind> kTouchBasedDeviceKinds = {
PointerDeviceKind.touch,
PointerDeviceKind.stylus,
PointerDeviceKind.invertedStylus,
};
// Scale custom related constants
const String kCustomScalePercentKey = 'custom_scale_percent'; // Flutter option key for storing custom scale percent (integer 5-1000)
const int kScaleCustomMinPercent = 5;
const int kScaleCustomPivotPercent = 100; // 100% should be at 1/3 of track
const int kScaleCustomMaxPercent = 1000;
const double kScaleCustomPivotPos = 1.0 / 3.0; // first 1/3 → up to 100%
const double kScaleCustomDetentEpsilon = 0.006; // snap range around pivot (~0.6%)
const Duration kDebounceCustomScaleDuration = Duration(milliseconds: 300);
// ================================ mobile ================================
// Magic numbers, maybe need to avoid it or use a better way to get them.

View File

@@ -2,10 +2,12 @@
import 'dart:async';
import 'dart:convert';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_hbb/common/widgets/connection_page_title.dart';
import 'package:flutter_hbb/consts.dart';
import 'package:flutter_hbb/desktop/widgets/popup_menu.dart';
import 'package:flutter_hbb/models/state_model.dart';
import 'package:get/get.dart';
import 'package:url_launcher/url_launcher_string.dart';
@@ -17,7 +19,7 @@ import '../../common/formatter/id_formatter.dart';
import '../../common/widgets/peer_tab_page.dart';
import '../../common/widgets/autocomplete.dart';
import '../../models/platform_model.dart';
import '../widgets/button.dart';
import '../../desktop/widgets/material_mod_popup_menu.dart' as mod_menu;
class OnlineStatusWidget extends StatefulWidget {
const OnlineStatusWidget({Key? key, this.onSvcStatusChanged})
@@ -39,7 +41,7 @@ class _OnlineStatusWidgetState extends State<OnlineStatusWidget> {
double? get height => bind.isIncomingOnly() ? null : em * 3;
void onUsePublicServerGuide() {
const url = "https://rustdesk.com/pricing.html";
const url = "https://rustdesk.com/pricing";
canLaunchUrlString(url).then((can) {
if (can) {
launchUrlString(url);
@@ -200,18 +202,25 @@ class _ConnectionPageState extends State<ConnectionPage>
final _idController = IDTextEditingController();
final RxBool _idInputFocused = false.obs;
final FocusNode _idFocusNode = FocusNode();
final TextEditingController _idEditingController = TextEditingController();
String selectedConnectionType = 'Connect';
bool isWindowMinimized = false;
List<Peer> peers = [];
bool isPeersLoading = false;
bool isPeersLoaded = false;
final AllPeersLoader _allPeersLoader = AllPeersLoader();
// https://github.com/flutter/flutter/issues/157244
Iterable<Peer> _autocompleteOpts = [];
final _menuOpen = false.obs;
@override
void initState() {
super.initState();
_allPeersLoader.init(setState);
_idFocusNode.addListener(onFocusChanged);
if (_idController.text.isEmpty) {
WidgetsBinding.instance.addPostFrameCallback((_) async {
final lastRemoteId = await bind.mainGetLastRemoteId();
@@ -222,6 +231,7 @@ class _ConnectionPageState extends State<ConnectionPage>
}
});
}
Get.put<TextEditingController>(_idEditingController);
Get.put<IDTextEditingController>(_idController);
windowManager.addListener(this);
}
@@ -230,6 +240,10 @@ class _ConnectionPageState extends State<ConnectionPage>
void dispose() {
_idController.dispose();
windowManager.removeListener(this);
_allPeersLoader.clear();
_idFocusNode.removeListener(onFocusChanged);
_idFocusNode.dispose();
_idEditingController.dispose();
if (Get.isRegistered<IDTextEditingController>()) {
Get.delete<IDTextEditingController>();
}
@@ -273,6 +287,20 @@ class _ConnectionPageState extends State<ConnectionPage>
bind.mainOnMainWindowClose();
}
void onFocusChanged() {
_idInputFocused.value = _idFocusNode.hasFocus;
if (_idFocusNode.hasFocus) {
if (_allPeersLoader.needLoad) {
_allPeersLoader.getAllPeers();
}
final textLength = _idEditingController.value.text.length;
// Select all to facilitate removing text, just following the behavior of address input of chrome.
_idEditingController.selection =
TextSelection(baseOffset: 0, extentOffset: textLength);
}
}
@override
Widget build(BuildContext context) {
final isOutgoingOnly = bind.isOutgoingOnly();
@@ -299,21 +327,15 @@ class _ConnectionPageState extends State<ConnectionPage>
/// Callback for the connect button.
/// Connects to the selected peer.
void onConnect({bool isFileTransfer = false}) {
void onConnect(
{bool isFileTransfer = false,
bool isViewCamera = false,
bool isTerminal = false}) {
var id = _idController.id;
connect(context, id, isFileTransfer: isFileTransfer);
}
Future<void> _fetchPeers() async {
setState(() {
isPeersLoading = true;
});
await Future.delayed(Duration(milliseconds: 100));
peers = await getAllPeers();
setState(() {
isPeersLoading = false;
isPeersLoaded = true;
});
connect(context, id,
isFileTransfer: isFileTransfer,
isViewCamera: isViewCamera,
isTerminal: isTerminal);
}
/// UI for the remote ID TextField.
@@ -332,11 +354,12 @@ class _ConnectionPageState extends State<ConnectionPage>
Row(
children: [
Expanded(
child: Autocomplete<Peer>(
child: RawAutocomplete<Peer>(
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text == '') {
_autocompleteOpts = const Iterable<Peer>.empty();
} else if (peers.isEmpty && !isPeersLoaded) {
} else if (_allPeersLoader.peers.isEmpty &&
!_allPeersLoader.isPeersLoaded) {
Peer emptyPeer = Peer(
id: '',
username: '',
@@ -350,6 +373,8 @@ class _ConnectionPageState extends State<ConnectionPage>
rdpPort: '',
rdpUsername: '',
loginName: '',
device_group_name: '',
note: '',
);
_autocompleteOpts = [emptyPeer];
} else {
@@ -362,7 +387,7 @@ class _ConnectionPageState extends State<ConnectionPage>
);
}
String textToFind = textEditingValue.text.toLowerCase();
_autocompleteOpts = peers
_autocompleteOpts = _allPeersLoader.peers
.where((peer) =>
peer.id.toLowerCase().contains(textToFind) ||
peer.username
@@ -376,25 +401,16 @@ class _ConnectionPageState extends State<ConnectionPage>
}
return _autocompleteOpts;
},
focusNode: _idFocusNode,
textEditingController: _idEditingController,
fieldViewBuilder: (
BuildContext context,
TextEditingController fieldTextEditingController,
FocusNode fieldFocusNode,
VoidCallback onFieldSubmitted,
) {
fieldTextEditingController.text = _idController.text;
Get.put<TextEditingController>(fieldTextEditingController);
fieldFocusNode.addListener(() async {
_idInputFocused.value = fieldFocusNode.hasFocus;
if (fieldFocusNode.hasFocus && !isPeersLoading) {
_fetchPeers();
}
});
final textLength =
fieldTextEditingController.value.text.length;
// select all to facilitate removing text, just following the behavior of address input of chrome
fieldTextEditingController.selection =
TextSelection(baseOffset: 0, extentOffset: textLength);
updateTextAndPreserveSelection(
fieldTextEditingController, _idController.text);
return Obx(() => TextField(
autocorrect: false,
enableSuggestions: false,
@@ -467,7 +483,8 @@ class _ConnectionPageState extends State<ConnectionPage>
maxHeight: maxHeight,
maxWidth: 319,
),
child: peers.isEmpty && isPeersLoading
child: _allPeersLoader.peers.isEmpty &&
!_allPeersLoader.isPeersLoaded
? Container(
height: 80,
child: Center(
@@ -497,21 +514,97 @@ class _ConnectionPageState extends State<ConnectionPage>
),
Padding(
padding: const EdgeInsets.only(top: 13.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Button(
isOutline: true,
onTap: () => onConnect(isFileTransfer: true),
text: "Transfer file",
child: Row(mainAxisAlignment: MainAxisAlignment.end, children: [
SizedBox(
height: 28.0,
child: ElevatedButton(
onPressed: () {
onConnect();
},
child: Text(translate("Connect")),
),
const SizedBox(
width: 17,
),
const SizedBox(width: 8),
Container(
height: 28.0,
width: 28.0,
decoration: BoxDecoration(
border: Border.all(color: Theme.of(context).dividerColor),
borderRadius: BorderRadius.circular(8),
),
Button(onTap: onConnect, text: "Connect"),
],
),
)
child: Center(
child: StatefulBuilder(
builder: (context, setState) {
var offset = Offset(0, 0);
return Obx(() => InkWell(
child: _menuOpen.value
? Transform.rotate(
angle: pi,
child: Icon(IconFont.more, size: 14),
)
: Icon(IconFont.more, size: 14),
onTapDown: (e) {
offset = e.globalPosition;
},
onTap: () async {
_menuOpen.value = true;
final x = offset.dx;
final y = offset.dy;
await mod_menu
.showMenu(
context: context,
position: RelativeRect.fromLTRB(x, y, x, y),
items: [
(
'Transfer file',
() => onConnect(isFileTransfer: true)
),
(
'View camera',
() => onConnect(isViewCamera: true)
),
(
'${translate('Terminal')} (beta)',
() => onConnect(isTerminal: true)
),
]
.map((e) => MenuEntryButton<String>(
childBuilder: (TextStyle? style) =>
Text(
translate(e.$1),
style: style,
),
proc: () => e.$2(),
padding: EdgeInsets.symmetric(
horizontal:
kDesktopMenuPadding.left),
dismissOnClicked: true,
))
.map((e) => e.build(
context,
const MenuConfig(
commonColor: CustomPopupMenuTheme
.commonColor,
height:
CustomPopupMenuTheme.height,
dividerHeight:
CustomPopupMenuTheme
.dividerHeight)))
.expand((i) => i)
.toList(),
elevation: 8,
)
.then((_) {
_menuOpen.value = false;
});
},
));
},
),
),
),
]),
),
],
),
),

View File

@@ -12,6 +12,7 @@ import 'package:flutter_hbb/consts.dart';
import 'package:flutter_hbb/desktop/pages/connection_page.dart';
import 'package:flutter_hbb/desktop/pages/desktop_setting_page.dart';
import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart';
import 'package:flutter_hbb/desktop/widgets/update_progress.dart';
import 'package:flutter_hbb/models/platform_model.dart';
import 'package:flutter_hbb/models/server_model.dart';
import 'package:flutter_hbb/models/state_model.dart';
@@ -22,7 +23,6 @@ import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:window_manager/window_manager.dart';
import 'package:window_size/window_size.dart' as window_size;
import '../widgets/button.dart';
class DesktopHomePage extends StatefulWidget {
@@ -134,12 +134,17 @@ class _DesktopHomePageState extends State<DesktopHomePage>
color: Theme.of(context).colorScheme.background,
child: Stack(
children: [
SingleChildScrollView(
controller: _leftPaneScrollController,
child: Column(
key: _childKey,
children: children,
),
Column(
children: [
SingleChildScrollView(
controller: _leftPaneScrollController,
child: Column(
key: _childKey,
children: children,
),
),
Expanded(child: Container())
],
),
if (isOutgoingOnly)
Positioned(
@@ -428,13 +433,23 @@ class _DesktopHomePageState extends State<DesktopHomePage>
updateUrl.isNotEmpty &&
!isCardClosed &&
bind.mainUriPrefixSync().contains('rustdesk')) {
final isToUpdate = (isWindows || isMacOS) && bind.mainIsInstalled();
String btnText = isToUpdate ? 'Update' : 'Download';
GestureTapCallback onPressed = () async {
final Uri url = Uri.parse('https://rustdesk.com/download');
await launchUrl(url);
};
if (isToUpdate) {
onPressed = () {
handleUpdate(updateUrl);
};
}
return buildInstallCard(
"Status",
"${translate("new-version-of-{${bind.mainGetAppNameSync()}}-tip")} (${bind.mainGetNewVersion()}).",
"Click to download", () async {
final Uri url = Uri.parse('https://rustdesk.com/download');
await launchUrl(url);
}, closeButton: true);
btnText,
onPressed,
closeButton: true);
}
if (systemError.isNotEmpty) {
return buildInstallCard("", systemError, "", () {});
@@ -770,6 +785,8 @@ class _DesktopHomePageState extends State<DesktopHomePage>
await connectMainDesktop(
call.arguments['id'],
isFileTransfer: call.arguments['isFileTransfer'],
isViewCamera: call.arguments['isViewCamera'],
isTerminal: call.arguments['isTerminal'],
isTcpTunneling: call.arguments['isTcpTunneling'],
isRDP: call.arguments['isRDP'],
password: call.arguments['password'],
@@ -784,9 +801,15 @@ class _DesktopHomePageState extends State<DesktopHomePage>
} catch (e) {
debugPrint("Failed to parse window id '${call.arguments}': $e");
}
if (windowId != null) {
WindowType? windowType;
try {
windowType = WindowType.values.byName(args[3]);
} catch (e) {
debugPrint("Failed to parse window type '${call.arguments}': $e");
}
if (windowId != null && windowType != null) {
await rustDeskWinManager.moveTabToNewWindow(
windowId, args[1], args[2]);
windowId, args[1], args[2], windowType);
}
} else if (call.method == kWindowEventOpenMonitorSession) {
final args = jsonDecode(call.arguments);
@@ -794,9 +817,10 @@ class _DesktopHomePageState extends State<DesktopHomePage>
final peerId = args['peer_id'] as String;
final display = args['display'] as int;
final displayCount = args['display_count'] as int;
final windowType = args['window_type'] as int;
final screenRect = parseParamScreenRect(args);
await rustDeskWinManager.openMonitorSession(
windowId, peerId, display, displayCount, screenRect);
windowId, peerId, display, displayCount, screenRect, windowType);
} else if (call.method == kWindowEventRemoteWindowCoords) {
final windowId = int.tryParse(call.arguments);
if (windowId != null) {
@@ -834,10 +858,6 @@ class _DesktopHomePageState extends State<DesktopHomePage>
_uniLinksSubscription?.cancel();
Get.delete<RxBool>(tag: 'stop-service');
_updateTimer?.cancel();
if (!bind.isCustomClient()) {
platformFFI.unregisterEventHandler(
kCheckSoftwareUpdateFinish, kCheckSoftwareUpdateFinish);
}
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}

View File

@@ -13,6 +13,7 @@ import 'package:flutter_hbb/desktop/pages/desktop_home_page.dart';
import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart';
import 'package:flutter_hbb/mobile/widgets/dialog.dart';
import 'package:flutter_hbb/models/platform_model.dart';
import 'package:flutter_hbb/models/printer_model.dart';
import 'package:flutter_hbb/models/server_model.dart';
import 'package:flutter_hbb/models/state_model.dart';
import 'package:flutter_hbb/plugin/manager.dart';
@@ -55,6 +56,7 @@ enum SettingsTabKey {
display,
plugin,
account,
printer,
about,
}
@@ -74,6 +76,9 @@ class DesktopSettingPage extends StatefulWidget {
if (!isWeb && !bind.isIncomingOnly() && bind.pluginFeatureIsEnabled())
SettingsTabKey.plugin,
if (!bind.isDisableAccount()) SettingsTabKey.account,
if (isWindows &&
bind.mainGetBuildinOption(key: kOptionHideRemotePrinterSetting) != 'Y')
SettingsTabKey.printer,
SettingsTabKey.about,
];
@@ -198,6 +203,10 @@ class _DesktopSettingPageState extends State<DesktopSettingPage>
settingTabs.add(
_TabInfo(tab, 'Account', Icons.person_outline, Icons.person));
break;
case SettingsTabKey.printer:
settingTabs
.add(_TabInfo(tab, 'Printer', Icons.print_outlined, Icons.print));
break;
case SettingsTabKey.about:
settingTabs
.add(_TabInfo(tab, 'About', Icons.info_outline, Icons.info));
@@ -229,6 +238,9 @@ class _DesktopSettingPageState extends State<DesktopSettingPage>
case SettingsTabKey.account:
children.add(const _Account());
break;
case SettingsTabKey.printer:
children.add(const _Printer());
break;
case SettingsTabKey.about:
children.add(const _About());
break;
@@ -460,6 +472,8 @@ class _GeneralState extends State<_General> {
}
Widget other() {
final showAutoUpdate =
isWindows && bind.mainIsInstalled() && !bind.isCustomClient();
final children = <Widget>[
if (!isWeb && !bind.isIncomingOnly())
_OptionCheckBox(context, 'Confirm before closing multiple tabs',
@@ -496,6 +510,16 @@ class _GeneralState extends State<_General> {
await bind.mainSetLocalOption(key: k, value: v ? 'Y' : 'N'),
),
),
if (isWindows)
Tooltip(
message: translate('d3d_render_tip'),
child: _OptionCheckBox(
context,
"Use D3D rendering",
kOptionD3DRender,
isServer: false,
),
),
if (!isWeb && !bind.isCustomClient())
_OptionCheckBox(
context,
@@ -503,12 +527,33 @@ class _GeneralState extends State<_General> {
kOptionEnableCheckUpdate,
isServer: false,
),
if (showAutoUpdate)
_OptionCheckBox(
context,
'Auto update',
kOptionAllowAutoUpdate,
isServer: true,
),
if (isWindows && !bind.isOutgoingOnly())
_OptionCheckBox(
context,
'Capture screen using DirectX',
kOptionDirectxCapture,
)
),
if (!bind.isIncomingOnly()) ...[
_OptionCheckBox(
context,
'Enable UDP hole punching',
kOptionEnableUdpPunch,
isServer: false,
),
_OptionCheckBox(
context,
'Enable IPv6 P2P connection',
kOptionEnableIpv6Punch,
isServer: false,
),
],
],
];
if (!isWeb && bind.mainShowOption(key: kOptionAllowLinuxHeadless)) {
@@ -607,7 +652,6 @@ class _GeneralState extends State<_General> {
bool user_dir_exists = await Directory(user_dir).exists();
bool root_dir_exists =
showRootDir ? await Directory(root_dir).exists() : false;
// canLaunchUrl blocked on windows portable, user SYSTEM
return {
'user_dir': user_dir,
'root_dir': root_dir,
@@ -954,6 +998,10 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
_OptionCheckBox(
context, 'Enable keyboard/mouse', kOptionEnableKeyboard,
enabled: enabled, fakeValue: fakeValue),
if (isWindows)
_OptionCheckBox(
context, 'Enable remote printer', kOptionEnableRemotePrinter,
enabled: enabled, fakeValue: fakeValue),
_OptionCheckBox(context, 'Enable clipboard', kOptionEnableClipboard,
enabled: enabled, fakeValue: fakeValue),
_OptionCheckBox(
@@ -961,6 +1009,10 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
enabled: enabled, fakeValue: fakeValue),
_OptionCheckBox(context, 'Enable audio', kOptionEnableAudio,
enabled: enabled, fakeValue: fakeValue),
_OptionCheckBox(context, 'Enable camera', kOptionEnableCamera,
enabled: enabled, fakeValue: fakeValue),
_OptionCheckBox(context, 'Enable terminal', kOptionEnableTerminal,
enabled: enabled, fakeValue: fakeValue),
_OptionCheckBox(
context, 'Enable TCP tunneling', kOptionEnableTunnel,
enabled: enabled, fakeValue: fakeValue),
@@ -1061,6 +1113,34 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
))
.toList();
final isOptFixedNumOTP =
isOptionFixed(kOptionAllowNumericOneTimePassword);
final isNumOPTChangable = !isOptFixedNumOTP && tmpEnabled && !locked;
final numericOneTimePassword = GestureDetector(
child: InkWell(
child: Row(
children: [
Checkbox(
value: model.allowNumericOneTimePassword,
onChanged: isNumOPTChangable
? (bool? v) {
model.switchAllowNumericOneTimePassword();
}
: null)
.marginOnly(right: 5),
Expanded(
child: Text(
translate('Numeric one-time password'),
style: TextStyle(
color: disabledTextColor(context, isNumOPTChangable)),
))
],
)),
onTap: isNumOPTChangable
? () => model.switchAllowNumericOneTimePassword()
: null,
).marginOnly(left: _kContentHSubMargin - 5);
final modeKeys = <String>[
'password',
'click',
@@ -1097,6 +1177,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
],
),
enabled: tmpEnabled && !locked),
numericOneTimePassword,
if (usePassword) radios[1],
if (usePassword)
_SubButton('Set permanent password', setPasswordDialog,
@@ -1441,11 +1522,69 @@ class _NetworkState extends State<_Network> with AutomaticKeepAliveClientMixin {
bind.mainGetBuildinOption(key: kOptionHideServerSetting) == 'Y';
final hideProxy =
isWeb || bind.mainGetBuildinOption(key: kOptionHideProxySetting) == 'Y';
final hideWebSocket = isWeb ||
bind.mainGetBuildinOption(key: kOptionHideWebSocketSetting) == 'Y';
if (hideServer && hideProxy) {
if (hideServer && hideProxy && hideWebSocket) {
return Offstage();
}
// Helper function to create network setting ListTiles
Widget listTile({
required IconData icon,
required String title,
VoidCallback? onTap,
Widget? trailing,
bool showTooltip = false,
String tooltipMessage = '',
}) {
final titleWidget = showTooltip
? Row(
children: [
Tooltip(
waitDuration: Duration(milliseconds: 1000),
message: translate(tooltipMessage),
child: Row(
children: [
Text(
translate(title),
style: TextStyle(fontSize: _kContentFontSize),
),
SizedBox(width: 5),
Icon(
Icons.help_outline,
size: 14,
color: Theme.of(context)
.textTheme
.titleLarge
?.color
?.withOpacity(0.7),
),
],
),
),
],
)
: Text(
translate(title),
style: TextStyle(fontSize: _kContentFontSize),
);
return ListTile(
leading: Icon(icon, color: _accentColor),
title: titleWidget,
enabled: !locked,
onTap: onTap,
trailing: trailing,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
contentPadding: EdgeInsets.symmetric(horizontal: 16),
minLeadingWidth: 0,
horizontalTitleGap: 10,
);
}
return _Card(
title: 'Network',
children: [
@@ -1454,39 +1593,36 @@ class _NetworkState extends State<_Network> with AutomaticKeepAliveClientMixin {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (!hideServer)
ListTile(
leading: Icon(Icons.dns_outlined, color: _accentColor),
title: Text(
translate('ID/Relay Server'),
style: TextStyle(fontSize: _kContentFontSize),
),
enabled: !locked,
listTile(
icon: Icons.dns_outlined,
title: 'ID/Relay Server',
onTap: () => showServerSettings(gFFI.dialogManager),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
contentPadding: EdgeInsets.symmetric(horizontal: 16),
minLeadingWidth: 0,
horizontalTitleGap: 10,
),
if (!hideServer && !hideProxy)
if (!hideServer && (!hideProxy || !hideWebSocket))
Divider(height: 1, indent: 16, endIndent: 16),
if (!hideProxy)
ListTile(
leading:
Icon(Icons.network_ping_outlined, color: _accentColor),
title: Text(
translate('Socks5/Http(s) Proxy'),
style: TextStyle(fontSize: _kContentFontSize),
),
enabled: !locked,
listTile(
icon: Icons.network_ping_outlined,
title: 'Socks5/Http(s) Proxy',
onTap: changeSocks5Proxy,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
if (!hideProxy && !hideWebSocket)
Divider(height: 1, indent: 16, endIndent: 16),
if (!hideWebSocket)
listTile(
icon: Icons.web_asset_outlined,
title: 'Use WebSocket',
showTooltip: true,
tooltipMessage: 'websocket_tip',
trailing: Switch(
value: mainGetBoolOptionSync(kOptionAllowWebSocket),
onChanged: locked
? null
: (value) {
mainSetBoolOption(kOptionAllowWebSocket, value);
setState(() {});
},
),
contentPadding: EdgeInsets.symmetric(horizontal: 16),
minLeadingWidth: 0,
horizontalTitleGap: 10,
),
],
),
@@ -1512,6 +1648,7 @@ class _DisplayState extends State<_Display> {
scrollStyle(context),
imageQuality(context),
codec(context),
if (isDesktop) trackpadSpeed(context),
if (!isWeb) privacyModeImpl(context),
other(context),
]).marginOnly(bottom: _kListViewBottomMargin);
@@ -1599,6 +1736,26 @@ class _DisplayState extends State<_Display> {
]);
}
Widget trackpadSpeed(BuildContext context) {
final initSpeed = (int.tryParse(
bind.mainGetUserDefaultOption(key: kKeyTrackpadSpeed)) ??
kDefaultTrackpadSpeed);
final curSpeed = SimpleWrapper(initSpeed);
void onDebouncer(int v) {
bind.mainSetUserDefaultOption(
key: kKeyTrackpadSpeed, value: v.toString());
// It's better to notify all sessions that the default speed is changed.
// But it may also be ok to take effect in the next connection.
}
return _Card(title: 'Default trackpad speed', children: [
TrackpadSpeedWidget(
value: curSpeed,
onDebouncer: onDebouncer,
),
]);
}
Widget codec(BuildContext context) {
onChanged(String value) async {
await bind.mainSetUserDefaultOption(
@@ -1870,6 +2027,153 @@ class _PluginState extends State<_Plugin> {
}
}
class _Printer extends StatefulWidget {
const _Printer({super.key});
@override
State<_Printer> createState() => __PrinterState();
}
class __PrinterState extends State<_Printer> {
@override
Widget build(BuildContext context) {
final scrollController = ScrollController();
return ListView(controller: scrollController, children: [
outgoing(context),
incoming(context),
]).marginOnly(bottom: _kListViewBottomMargin);
}
Widget outgoing(BuildContext context) {
final isSupportPrinterDriver =
bind.mainGetCommonSync(key: 'is-support-printer-driver') == 'true';
Widget tipOsNotSupported() {
return Align(
alignment: Alignment.topLeft,
child: Text(translate('printer-os-requirement-tip')),
).marginOnly(left: _kCardLeftMargin);
}
Widget tipClientNotInstalled() {
return Align(
alignment: Alignment.topLeft,
child:
Text(translate('printer-requires-installed-{$appName}-client-tip')),
).marginOnly(left: _kCardLeftMargin);
}
Widget tipPrinterNotInstalled() {
final failedMsg = ''.obs;
platformFFI.registerEventHandler(
'install-printer-res', 'install-printer-res', (evt) async {
if (evt['success'] as bool) {
setState(() {});
} else {
failedMsg.value = evt['msg'] as String;
}
}, replace: true);
return Column(children: [
Obx(
() => failedMsg.value.isNotEmpty
? Offstage()
: Align(
alignment: Alignment.topLeft,
child: Text(translate('printer-{$appName}-not-installed-tip'))
.marginOnly(bottom: 10.0),
),
),
Obx(
() => failedMsg.value.isEmpty
? Offstage()
: Align(
alignment: Alignment.topLeft,
child: Text(failedMsg.value,
style: DefaultTextStyle.of(context)
.style
.copyWith(color: Colors.red))
.marginOnly(bottom: 10.0)),
),
_Button('Install {$appName} Printer', () {
failedMsg.value = '';
bind.mainSetCommon(key: 'install-printer', value: '');
})
]).marginOnly(left: _kCardLeftMargin, bottom: 2.0);
}
Widget tipReady() {
return Align(
alignment: Alignment.topLeft,
child: Text(translate('printer-{$appName}-ready-tip')),
).marginOnly(left: _kCardLeftMargin);
}
final installed = bind.mainIsInstalled();
// `is-printer-installed` may fail, but it's rare case.
// Add additional error message here if it's really needed.
final isPrinterInstalled =
bind.mainGetCommonSync(key: 'is-printer-installed') == 'true';
final List<Widget> children = [];
if (!isSupportPrinterDriver) {
children.add(tipOsNotSupported());
} else {
children.addAll([
if (!installed) tipClientNotInstalled(),
if (installed && !isPrinterInstalled) tipPrinterNotInstalled(),
if (installed && isPrinterInstalled) tipReady()
]);
}
return _Card(title: 'Outgoing Print Jobs', children: children);
}
Widget incoming(BuildContext context) {
onRadioChanged(String value) async {
await bind.mainSetLocalOption(
key: kKeyPrinterIncomingJobAction, value: value);
setState(() {});
}
PrinterOptions printerOptions = PrinterOptions.load();
return _Card(title: 'Incoming Print Jobs', children: [
_Radio(context,
value: kValuePrinterIncomingJobDismiss,
groupValue: printerOptions.action,
label: 'Dismiss',
onChanged: onRadioChanged),
_Radio(context,
value: kValuePrinterIncomingJobDefault,
groupValue: printerOptions.action,
label: 'use-the-default-printer-tip',
onChanged: onRadioChanged),
_Radio(context,
value: kValuePrinterIncomingJobSelected,
groupValue: printerOptions.action,
label: 'use-the-selected-printer-tip',
onChanged: onRadioChanged),
if (printerOptions.printerNames.isNotEmpty)
ComboBox(
initialKey: printerOptions.printerName,
keys: printerOptions.printerNames,
values: printerOptions.printerNames,
enabled: printerOptions.action == kValuePrinterIncomingJobSelected,
onChanged: (value) async {
await bind.mainSetLocalOption(
key: kKeyPrinterSelected, value: value);
setState(() {});
},
).marginOnly(left: 10),
_OptionCheckBox(
context,
'auto-print-tip',
kKeyPrinterAllowAutoPrint,
isServer: false,
enabled: printerOptions.action != kValuePrinterIncomingJobDismiss,
)
]);
}
}
class _About extends StatefulWidget {
const _About({Key? key}) : super(key: key);

View File

@@ -103,11 +103,13 @@ class _FileManagerTabPageState extends State<FileManagerTabPage> {
));
final tabWidget = isLinux
? buildVirtualWindowFrame(context, child)
: Container(
decoration: BoxDecoration(
border: Border.all(color: MyTheme.color(context).border!)),
child: child,
);
: workaroundWindowBorder(
context,
Container(
decoration: BoxDecoration(
border: Border.all(color: MyTheme.color(context).border!)),
child: child,
));
return isMacOS || kUseCompatibleUiMode
? tabWidget
: SubWindowDragToResizeArea(

View File

@@ -65,6 +65,7 @@ class _InstallPageBodyState extends State<_InstallPageBody>
late final TextEditingController controller;
final RxBool startmenu = true.obs;
final RxBool desktopicon = true.obs;
final RxBool printer = true.obs;
final RxBool showProgress = false.obs;
final RxBool btnEnabled = true.obs;
@@ -79,6 +80,7 @@ class _InstallPageBodyState extends State<_InstallPageBody>
final installOptions = jsonDecode(bind.installInstallOptions());
startmenu.value = installOptions['STARTMENUSHORTCUTS'] != '0';
desktopicon.value = installOptions['DESKTOPSHORTCUTS'] != '0';
printer.value = installOptions['PRINTER'] != '0';
}
@override
@@ -161,7 +163,9 @@ class _InstallPageBodyState extends State<_InstallPageBody>
).marginSymmetric(vertical: 2 * em),
Option(startmenu, label: 'Create start menu shortcuts')
.marginOnly(bottom: 7),
Option(desktopicon, label: 'Create desktop icon'),
Option(desktopicon, label: 'Create desktop icon')
.marginOnly(bottom: 7),
Option(printer, label: 'Install {$appName} Printer'),
Container(
padding: EdgeInsets.all(12),
decoration: BoxDecoration(
@@ -253,6 +257,7 @@ class _InstallPageBodyState extends State<_InstallPageBody>
String args = '';
if (startmenu.value) args += ' startmenu';
if (desktopicon.value) args += ' desktopicon';
if (printer.value) args += ' printer';
bind.installInstallMe(options: args, path: controller.text);
}

View File

@@ -118,11 +118,13 @@ class _PortForwardTabPageState extends State<PortForwardTabPage> {
backgroundColor: Theme.of(context).colorScheme.background,
body: child),
)
: Container(
decoration: BoxDecoration(
border: Border.all(color: MyTheme.color(context).border!)),
child: child,
);
: workaroundWindowBorder(
context,
Container(
decoration: BoxDecoration(
border: Border.all(color: MyTheme.color(context).border!)),
child: child,
));
return isMacOS || kUseCompatibleUiMode
? tabWidget
: Obx(

View File

@@ -146,16 +146,8 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
connectionType.secure.value == ConnectionType.strSecure;
bool direct =
connectionType.direct.value == ConnectionType.strDirect;
String msgConn;
if (secure && direct) {
msgConn = translate("Direct and encrypted connection");
} else if (secure && !direct) {
msgConn = translate("Relayed and encrypted connection");
} else if (!secure && direct) {
msgConn = translate("Direct and unencrypted connection");
} else {
msgConn = translate("Relayed and unencrypted connection");
}
String msgConn = getConnectionText(
secure, direct, connectionType.stream_type.value);
var msgFingerprint = '${translate('Fingerprint')}:\n';
var fingerprint = FingerprintState.find(key).value;
if (fingerprint.isEmpty) {
@@ -212,14 +204,16 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
);
final tabWidget = isLinux
? buildVirtualWindowFrame(context, child)
: Obx(() => Container(
decoration: BoxDecoration(
border: Border.all(
color: MyTheme.color(context).border!,
width: stateGlobal.windowBorderWidth.value),
),
child: child,
));
: workaroundWindowBorder(
context,
Obx(() => Container(
decoration: BoxDecoration(
border: Border.all(
color: MyTheme.color(context).border!,
width: stateGlobal.windowBorderWidth.value),
),
child: child,
)));
return isMacOS || kUseCompatibleUiMode
? tabWidget
: Obx(() => SubWindowDragToResizeArea(
@@ -267,8 +261,10 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
style: style,
),
proc: () async {
await DesktopMultiWindow.invokeMethod(kMainWindowId,
kWindowEventMoveTabToNewWindow, '${windowId()},$key,$sessionId');
await DesktopMultiWindow.invokeMethod(
kMainWindowId,
kWindowEventMoveTabToNewWindow,
'${windowId()},$key,$sessionId,RemoteDesktop');
cancelFunc();
},
padding: padding,
@@ -415,8 +411,8 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
await WindowController.fromWindowId(windowId()).setFullscreen(false);
stateGlobal.setFullscreen(false, procWnd: false);
}
await setNewConnectWindowFrame(
windowId(), id!, prePeerCount, display, screenRect);
await setNewConnectWindowFrame(windowId(), id!, prePeerCount,
WindowType.RemoteDesktop, display, screenRect);
Future.delayed(Duration(milliseconds: isWindows ? 100 : 0), () async {
await windowOnTop(windowId());
});

Some files were not shown because too many files have changed in this diff Show More