This commit is contained in:
night-hood 2026-04-18 11:00:05 +08:00 committed by GitHub
commit 9f5ff92d96
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 239 additions and 27 deletions

177
.github/workflows/linux-test-build.yml vendored Normal file
View file

@ -0,0 +1,177 @@
name: Linux Test Build
on:
workflow_dispatch:
push:
branches:
- fix/wayland-ext-data-control
env:
RUST_VERSION: "1.75"
FLUTTER_VERSION: "3.24.5"
VCPKG_COMMIT_ID: "120deac3062162151622ca4860575a33844ba10b"
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
jobs:
generate-bridge:
uses: ./.github/workflows/bridge.yml
build-linux-x86_64:
needs: [generate-bridge]
runs-on: ubuntu-22.04
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: Free Disk Space
uses: jlumbroso/free-disk-space@v1.3.1
with:
tool-cache: false
android: true
dotnet: true
haskell: true
large-packages: false
docker-images: true
swap-storage: false
- name: Checkout source code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Restore bridge files
uses: actions/download-artifact@v4
with:
name: bridge-artifact
path: ./
- name: Install prerequisites
shell: bash
run: |
sudo apt-get update -y
sudo apt-get install -y \
clang \
cmake \
curl \
gcc \
git \
g++ \
libayatana-appindicator3-dev \
libasound2-dev \
libclang-dev \
libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-dev \
libgtk-3-dev \
libpam0g-dev \
libpulse-dev \
libssl-dev \
libunwind-dev \
libva-dev \
libvdpau-dev \
libxcb-randr0-dev \
libxcb-shape0-dev \
libxcb-xfixes0-dev \
libxdo-dev \
libxfixes-dev \
nasm \
ninja-build \
pkg-config \
python3 \
rpm \
unzip \
wget \
xz-utils
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@v1
with:
toolchain: ${{ env.RUST_VERSION }}
targets: x86_64-unknown-linux-gnu
components: "rustfmt"
- uses: Swatinem/rust-cache@v2
with:
prefix-key: linux-test-ubuntu-22.04
- name: Disable rust bridge build
shell: bash
run: |
sed -i 's/\["cdylib", "staticlib", "rlib"\]/\["cdylib"\]/g' Cargo.toml
- name: Setup vcpkg with GitHub Actions cache
uses: lukka/run-vcpkg@v11
with:
vcpkgDirectory: /opt/artifacts/vcpkg
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
doNotCache: false
- name: Install vcpkg dependencies
shell: bash
run: |
if ! $VCPKG_ROOT/vcpkg \
install \
--triplet x64-linux \
--x-install-root="$VCPKG_ROOT/installed"; then
find "${VCPKG_ROOT}/" -name "*.log" | while read -r _1; do
echo "$_1:"
echo "======"
cat "$_1"
echo "======"
echo ""
done
exit 1
fi
head -n 100 "${VCPKG_ROOT}/buildtrees/ffmpeg/build-x64-linux-rel-out.log" || true
- name: Install flutter
uses: subosito/flutter-action@v2.12.0
with:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- name: Patch flutter
shell: bash
run: |
FLUTTER_DIR="$(dirname "$(dirname "$(which flutter)")")"
PATCH_FILE="${{ github.workspace }}/.github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff"
cp "$PATCH_FILE" "$FLUTTER_DIR"
pushd "$FLUTTER_DIR"
if git apply --check flutter_3.24.4_dropdown_menu_enableFilter.diff; then
git apply flutter_3.24.4_dropdown_menu_enableFilter.diff
else
echo "Skipping outdated flutter patch for Flutter ${{ env.FLUTTER_VERSION }}"
fi
popd
- name: Build rustdesk core
shell: bash
run: |
cargo build --lib --features hwcodec,flutter,unix-file-copy-paste --release
- name: Build linux bundle and package
shell: bash
run: |
export CARGO_INCREMENTAL=0
export DEB_ARCH=amd64
python3 ./build.py --flutter --skip-cargo
tar -C flutter/build/linux/x64/release -czf rustdesk-linux-x86_64-bundle.tar.gz bundle
deb_file=$(ls rustdesk-*.deb | head -n1)
cp "$deb_file" rustdesk-linux-x86_64.deb
ls -lh rustdesk-linux-x86_64-bundle.tar.gz rustdesk-linux-x86_64.deb
- name: Upload linux bundle
uses: actions/upload-artifact@v4
with:
name: rustdesk-linux-x86_64-bundle
path: rustdesk-linux-x86_64-bundle.tar.gz
- name: Upload deb package
uses: actions/upload-artifact@v4
with:
name: rustdesk-linux-x86_64-deb
path: rustdesk-linux-x86_64.deb

34
Cargo.lock generated
View file

@ -1324,7 +1324,7 @@ dependencies = [
[[package]]
name = "clipboard-master"
version = "4.0.0-beta.6"
source = "git+https://github.com/rustdesk-org/clipboard-master#ddc39f00a6211959489ae683aa6ae6eedf03a809"
source = "git+https://github.com/night-hood/clipboard-master?branch=fix/ext-data-control-v1#c2e9f129cfd9179ace1a340d193aaa9556c2ed71"
dependencies = [
"objc",
"objc-foundation",
@ -2282,7 +2282,7 @@ dependencies = [
"libc",
"option-ext",
"redox_users 0.5.2",
"windows-sys 0.61.2",
"windows-sys 0.60.2",
]
[[package]]
@ -2694,7 +2694,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.52.0",
"windows-sys 0.60.2",
]
[[package]]
@ -6673,7 +6673,7 @@ dependencies = [
"once_cell",
"socket2 0.5.10",
"tracing",
"windows-sys 0.52.0",
"windows-sys 0.60.2",
]
[[package]]
@ -7457,7 +7457,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys 0.11.0",
"windows-sys 0.52.0",
"windows-sys 0.60.2",
]
[[package]]
@ -7514,7 +7514,7 @@ dependencies = [
"security-framework 3.5.1",
"security-framework-sys",
"webpki-root-certs",
"windows-sys 0.52.0",
"windows-sys 0.60.2",
]
[[package]]
@ -9733,9 +9733,9 @@ dependencies = [
[[package]]
name = "wayland-protocols-wlr"
version = "0.3.3"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd993de54a40a40fbe5601d9f1fbcaef0aebcc5fda447d7dc8f6dcbaae4f8953"
checksum = "efd94963ed43cf9938a090ca4f7da58eb55325ec8200c3848963e98dc25b78ec"
dependencies = [
"bitflags 2.9.1",
"wayland-backend",
@ -10408,15 +10408,6 @@ dependencies = [
"windows-targets 0.53.5",
]
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link 0.2.1",
]
[[package]]
name = "windows-targets"
version = "0.42.2"
@ -10838,16 +10829,15 @@ dependencies = [
[[package]]
name = "wl-clipboard-rs"
version = "0.9.0"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4de22eebb1d1e2bad2d970086e96da0e12cde0b411321e5b0f7b2a1f876aa26f"
checksum = "e9651471a32e87d96ef3a127715382b2d11cc7c8bb9822ded8a7cc94072eb0a3"
dependencies = [
"libc",
"log",
"os_pipe",
"rustix 0.38.34",
"tempfile",
"thiserror 1.0.61",
"rustix 1.1.2",
"thiserror 2.0.17",
"tree_magic_mini",
"wayland-backend",
"wayland-client",

View file

@ -98,7 +98,7 @@ clipboard = { path = "libs/clipboard" }
ctrlc = "3.2"
# 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" }
clipboard-master = { git = "https://github.com/night-hood/clipboard-master", branch = "fix/ext-data-control-v1" }
portable-pty = { git = "https://github.com/rustdesk-org/wezterm", branch = "rustdesk/pty_based_0.8.1", package = "portable-pty" }
system_shutdown = "4.0"

View file

@ -986,6 +986,7 @@ impl Client {
std::thread::spawn(move || {
let mut handler = ClientClipboardHandler {
ctx: None,
last_sent_clipboard_sig: None,
#[cfg(not(feature = "flutter"))]
client_clip_ctx: _client_clip_ctx,
};
@ -1007,7 +1008,12 @@ impl Client {
log::error!("Clipboard listener stopped with error: {}", err);
break;
}
Err(RecvTimeoutError::Timeout) => {}
Err(RecvTimeoutError::Timeout) => {
#[cfg(target_os = "linux")]
if !crate::platform::linux::is_x11() {
handler.check_clipboard();
}
}
Err(RecvTimeoutError::Disconnected) => {
log::error!("Clipboard listener disconnected");
break;
@ -1070,12 +1076,25 @@ impl ClipboardState {
#[cfg(not(any(target_os = "android", target_os = "ios")))]
struct ClientClipboardHandler {
ctx: Option<crate::clipboard::ClipboardContext>,
last_sent_clipboard_sig: Option<Vec<u8>>,
#[cfg(not(feature = "flutter"))]
client_clip_ctx: Option<ClientClipboardContext>,
}
#[cfg(not(any(target_os = "android", target_os = "ios")))]
impl ClientClipboardHandler {
fn should_send_msg(&mut self, msg: &Message) -> bool {
use hbb_common::protobuf::Message as _;
let Ok(sig) = msg.write_to_bytes() else {
return true;
};
if self.last_sent_clipboard_sig.as_ref() == Some(&sig) {
return false;
}
self.last_sent_clipboard_sig = Some(sig);
true
}
fn is_text_required(&self) -> bool {
#[cfg(feature = "flutter")]
{
@ -1132,7 +1151,7 @@ impl ClientClipboardHandler {
}
if let Some(msg) = check_clipboard(&mut self.ctx, ClipboardSide::Client, false) {
if self.is_text_required() {
if self.is_text_required() && self.should_send_msg(&msg) {
self.send_msg(msg, false);
}
}

View file

@ -26,6 +26,8 @@ use std::{
};
#[cfg(windows)]
use tokio::runtime::Runtime;
#[cfg(not(target_os = "android"))]
use hbb_common::protobuf::Message as _;
#[cfg(target_os = "android")]
static CLIPBOARD_SERVICE_OK: AtomicBool = AtomicBool::new(false);
@ -33,6 +35,7 @@ static CLIPBOARD_SERVICE_OK: AtomicBool = AtomicBool::new(false);
#[cfg(not(target_os = "android"))]
struct Handler {
ctx: Option<ClipboardContext>,
last_clipboard_sig: Option<Vec<u8>>,
#[cfg(target_os = "windows")]
stream: Option<ipc::ConnectionTmpl<parity_tokio_ipc::ConnectionClient>>,
#[cfg(target_os = "windows")]
@ -71,6 +74,7 @@ fn run(sp: EmptyExtraFieldService) -> ResultType<()> {
clipboard_listener::subscribe(sp.name(), tx_cb_result)?;
let mut handler = Handler {
ctx,
last_clipboard_sig: None,
#[cfg(target_os = "windows")]
stream: None,
#[cfg(target_os = "windows")]
@ -86,7 +90,9 @@ fn run(sp: EmptyExtraFieldService) -> ResultType<()> {
continue;
}
if let Some(msg) = handler.get_clipboard_msg() {
sp.send(msg);
if handler.should_send_clipboard_msg(&msg) {
sp.send(msg);
}
}
}
Ok(CallbackResult::Stop) => {
@ -96,7 +102,16 @@ fn run(sp: EmptyExtraFieldService) -> ResultType<()> {
Ok(CallbackResult::StopWithError(err)) => {
bail!("Clipboard listener stopped with error: {}", err);
}
Err(RecvTimeoutError::Timeout) => {}
Err(RecvTimeoutError::Timeout) => {
#[cfg(target_os = "linux")]
if !crate::platform::linux::is_x11() && sp.name() == NAME {
if let Some(msg) = handler.get_clipboard_msg() {
if handler.should_send_clipboard_msg(&msg) {
sp.send(msg);
}
}
}
}
Err(RecvTimeoutError::Disconnected) => {
log::error!("Clipboard listener disconnected");
break;
@ -111,6 +126,17 @@ fn run(sp: EmptyExtraFieldService) -> ResultType<()> {
#[cfg(not(target_os = "android"))]
impl Handler {
fn should_send_clipboard_msg(&mut self, msg: &Message) -> bool {
let Ok(sig) = msg.write_to_bytes() else {
return true;
};
if self.last_clipboard_sig.as_ref() == Some(&sig) {
return false;
}
self.last_clipboard_sig = Some(sig);
true
}
#[cfg(feature = "unix-file-copy-paste")]
fn check_clipboard_file(&mut self) {
if let Some(urls) = check_clipboard_files(&mut self.ctx, ClipboardSide::Host, false) {