mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-09-14 00:11:01 +03:00
Report Linux cursor density independently of the host UI
This commit is contained in:
@@ -25,7 +25,7 @@ inline = []
|
|||||||
use_samplerate = ["samplerate"]
|
use_samplerate = ["samplerate"]
|
||||||
use_rubato = ["rubato"]
|
use_rubato = ["rubato"]
|
||||||
use_dasp = ["dasp"]
|
use_dasp = ["dasp"]
|
||||||
flutter = ["flutter_rust_bridge", "dep:x11rb"]
|
flutter = ["flutter_rust_bridge"]
|
||||||
default = ["use_dasp"]
|
default = ["use_dasp"]
|
||||||
hwcodec = ["scrap/hwcodec"]
|
hwcodec = ["scrap/hwcodec"]
|
||||||
vram = ["scrap/vram"]
|
vram = ["scrap/vram"]
|
||||||
@@ -40,7 +40,6 @@ drm-wake = ["drm"]
|
|||||||
linux-pkg-config = ["magnum-opus/linux-pkg-config", "scrap/linux-pkg-config"]
|
linux-pkg-config = ["magnum-opus/linux-pkg-config", "scrap/linux-pkg-config"]
|
||||||
unix-file-copy-paste = [
|
unix-file-copy-paste = [
|
||||||
"dep:x11-clipboard",
|
"dep:x11-clipboard",
|
||||||
"dep:x11rb",
|
|
||||||
"dep:percent-encoding",
|
"dep:percent-encoding",
|
||||||
"dep:once_cell",
|
"dep:once_cell",
|
||||||
"clipboard/unix-file-copy-paste",
|
"clipboard/unix-file-copy-paste",
|
||||||
@@ -191,7 +190,7 @@ evdev = { git="https://github.com/rustdesk-org/evdev" }
|
|||||||
dbus = "0.9"
|
dbus = "0.9"
|
||||||
dbus-crossroads = "0.5"
|
dbus-crossroads = "0.5"
|
||||||
x11-clipboard = {git="https://github.com/clslaid/x11-clipboard", branch = "feat/store-batch", optional = true}
|
x11-clipboard = {git="https://github.com/clslaid/x11-clipboard", branch = "feat/store-batch", optional = true}
|
||||||
x11rb = {version = "0.12", features = ["all-extensions"], optional = true}
|
x11rb = {version = "0.12", features = ["all-extensions"]}
|
||||||
percent-encoding = {version = "2.3", optional = true}
|
percent-encoding = {version = "2.3", optional = true}
|
||||||
once_cell = {version = "1.18", optional = true}
|
once_cell = {version = "1.18", optional = true}
|
||||||
nix = { version = "0.29", features = ["term", "process"]}
|
nix = { version = "0.29", features = ["term", "process"]}
|
||||||
|
|||||||
@@ -35,11 +35,7 @@ use std::{
|
|||||||
use terminfo::{capability as cap, Database};
|
use terminfo::{capability as cap, Database};
|
||||||
use wallpaper;
|
use wallpaper;
|
||||||
|
|
||||||
// Scope density lookup to Flutter host builds to preserve legacy capture
|
// Cursor density is capture metadata, independent of either endpoint's UI.
|
||||||
// behavior. These builds include density in cursor IDs to refresh on DPI
|
|
||||||
// changes; non-Flutter builds retain original IDs and unknown density.
|
|
||||||
// This gate describes the host binary, not the connected controller's UI.
|
|
||||||
#[cfg(feature = "flutter")]
|
|
||||||
mod cursor;
|
mod cursor;
|
||||||
|
|
||||||
pub const PA_SAMPLE_RATE: u32 = 48000;
|
pub const PA_SAMPLE_RATE: u32 = 48000;
|
||||||
@@ -577,11 +573,8 @@ pub fn get_cursor() -> ResultType<Option<u64>> {
|
|||||||
// polled there is a live session, which is the case the latch reads correctly.
|
// polled there is a live session, which is the case the latch reads correctly.
|
||||||
#[cfg(feature = "drm")]
|
#[cfg(feature = "drm")]
|
||||||
if !is_x11() {
|
if !is_x11() {
|
||||||
#[cfg(feature = "flutter")]
|
|
||||||
let cursor = cursor::drm_snapshot(|c| c.id)?
|
let cursor = cursor::drm_snapshot(|c| c.id)?
|
||||||
.map(|(id, scale)| cursor::cache_id(id, scale));
|
.map(|(id, scale)| cursor::cache_id(id, scale));
|
||||||
#[cfg(not(feature = "flutter"))]
|
|
||||||
let cursor = crate::server::drm_capturer::drm_cursor_id();
|
|
||||||
if let Some(id) = cursor {
|
if let Some(id) = cursor {
|
||||||
// In a mixed DRM + PipeWire session the DRM streams only cover the DRM-backed displays;
|
// In a mixed DRM + PipeWire session the DRM streams only cover the DRM-backed displays;
|
||||||
// when the pointer sits on a PipeWire-served display every DRM stream reports the hidden
|
// when the pointer sits on a PipeWire-served display every DRM stream reports the hidden
|
||||||
@@ -610,7 +603,6 @@ pub fn get_cursor() -> ResultType<Option<u64>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
#[cfg(feature = "flutter")]
|
|
||||||
let res = res.map(cursor::x11_cursor_id);
|
let res = res.map(cursor::x11_cursor_id);
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
@@ -624,13 +616,8 @@ pub fn get_cursor_data(hcursor: u64) -> ResultType<CursorData> {
|
|||||||
// agree anyway, since a caller that took the DRM branch there has to take it here.
|
// agree anyway, since a caller that took the DRM branch there has to take it here.
|
||||||
#[cfg(feature = "drm")]
|
#[cfg(feature = "drm")]
|
||||||
if !is_x11() {
|
if !is_x11() {
|
||||||
#[cfg(feature = "flutter")]
|
|
||||||
let cursor = cursor::drm_snapshot(Clone::clone)?;
|
let cursor = cursor::drm_snapshot(Clone::clone)?;
|
||||||
#[cfg(not(feature = "flutter"))]
|
if let Some((c, scale)) = cursor {
|
||||||
let cursor = crate::server::drm_capturer::drm_cursor();
|
|
||||||
if let Some(c) = cursor {
|
|
||||||
#[cfg(feature = "flutter")]
|
|
||||||
let (c, scale) = c;
|
|
||||||
// See get_cursor(): a hidden DRM sentinel is authoritative only in a pure-DRM session. In
|
// See get_cursor(): a hidden DRM sentinel is authoritative only in a pure-DRM session. In
|
||||||
// a mixed DRM + PipeWire session fall through so the PipeWire display's cursor is served
|
// a mixed DRM + PipeWire session fall through so the PipeWire display's cursor is served
|
||||||
// by the normal path instead of being hidden everywhere.
|
// by the normal path instead of being hidden everywhere.
|
||||||
@@ -638,27 +625,19 @@ pub fn get_cursor_data(hcursor: u64) -> ResultType<CursorData> {
|
|||||||
|| !crate::server::display_service::has_non_drm_backed_display()
|
|| !crate::server::display_service::has_non_drm_backed_display()
|
||||||
{
|
{
|
||||||
let mut cd: CursorData = Default::default();
|
let mut cd: CursorData = Default::default();
|
||||||
cd.id = c.id;
|
cd.id = cursor::cache_id(c.id, scale);
|
||||||
|
cd.scale = scale;
|
||||||
cd.width = c.width;
|
cd.width = c.width;
|
||||||
cd.height = c.height;
|
cd.height = c.height;
|
||||||
cd.hotx = c.hotx;
|
cd.hotx = c.hotx;
|
||||||
cd.hoty = c.hoty;
|
cd.hoty = c.hoty;
|
||||||
cd.colors = c.colors.into();
|
cd.colors = c.colors.into();
|
||||||
#[cfg(feature = "flutter")]
|
|
||||||
{
|
|
||||||
cd.id = cursor::cache_id(cd.id, scale);
|
|
||||||
cd.scale = scale;
|
|
||||||
}
|
|
||||||
return Ok(cd);
|
return Ok(cd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(feature = "flutter")]
|
|
||||||
let scale = cursor::x11_cursor_scale();
|
let scale = cursor::x11_cursor_scale();
|
||||||
#[cfg(feature = "flutter")]
|
|
||||||
let matches = |id| cursor::cache_id(id, scale) == hcursor;
|
let matches = |id| cursor::cache_id(id, scale) == hcursor;
|
||||||
#[cfg(not(feature = "flutter"))]
|
|
||||||
let matches = |id| id == hcursor;
|
|
||||||
let mut res = None;
|
let mut res = None;
|
||||||
DISPLAY.with(|conn| {
|
DISPLAY.with(|conn| {
|
||||||
if let Ok(ref mut d) = conn.try_borrow_mut() {
|
if let Ok(ref mut d) = conn.try_borrow_mut() {
|
||||||
@@ -673,10 +652,7 @@ pub fn get_cursor_data(hcursor: u64) -> ResultType<CursorData> {
|
|||||||
cd.height = (*img).height as _;
|
cd.height = (*img).height as _;
|
||||||
// to-do: how about if it is 0
|
// to-do: how about if it is 0
|
||||||
cd.id = hcursor;
|
cd.id = hcursor;
|
||||||
#[cfg(feature = "flutter")]
|
cd.scale = scale;
|
||||||
{
|
|
||||||
cd.scale = scale;
|
|
||||||
}
|
|
||||||
let pixels =
|
let pixels =
|
||||||
std::slice::from_raw_parts((*img).pixels, (cd.width * cd.height) as _);
|
std::slice::from_raw_parts((*img).pixels, (cd.width * cd.height) as _);
|
||||||
// cd.colors.resize(pixels.len() * 4, 0);
|
// cd.colors.resize(pixels.len() * 4, 0);
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ use std::sync::atomic::{AtomicBool, Ordering};
|
|||||||
use std::sync::{Arc, Condvar, Mutex};
|
use std::sync::{Arc, Condvar, Mutex};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
#[cfg(feature = "flutter")]
|
|
||||||
mod cursor_metadata;
|
mod cursor_metadata;
|
||||||
|
|
||||||
const HANDSHAKE_TIMEOUT_MS: u64 = 3000;
|
const HANDSHAKE_TIMEOUT_MS: u64 = 3000;
|
||||||
@@ -958,26 +957,8 @@ fn fold_cursor_id(id: u64, t: i32) -> u64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_drm_cursor<T>(f: impl Fn(&DrmCursorData) -> T) -> Option<T> {
|
/// Snapshot of the DRM hardware cursor and optional display metadata. Pixels retain the
|
||||||
let map = DRM_CURSOR.lock().unwrap();
|
/// premultiplied format used by the XFixes path.
|
||||||
map.values()
|
|
||||||
.map(|(_, c)| c)
|
|
||||||
.find(|c| c.id != scrap::drm_reader::HIDDEN_CURSOR_ID)
|
|
||||||
.or_else(|| map.values().map(|(_, c)| c).next())
|
|
||||||
.map(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn drm_cursor_id() -> Option<u64> {
|
|
||||||
with_drm_cursor(|c| c.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Snapshot of the DRM hardware cursor, or None. The pixels are premultiplied ARGB and are passed
|
|
||||||
/// through as-is, like the XFixes path, so the client sees one cursor format from either backend.
|
|
||||||
pub fn drm_cursor() -> Option<DrmCursorData> {
|
|
||||||
with_drm_cursor(|c| c.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "flutter")]
|
|
||||||
pub fn drm_cursor_snapshot<T>(
|
pub fn drm_cursor_snapshot<T>(
|
||||||
f: impl Fn(&DrmCursorData) -> T,
|
f: impl Fn(&DrmCursorData) -> T,
|
||||||
) -> Option<(T, Option<base::platform::linux::WaylandDisplayInfo>)> {
|
) -> Option<(T, Option<base::platform::linux::WaylandDisplayInfo>)> {
|
||||||
@@ -1019,7 +1000,6 @@ pub fn drm_cursor_snapshot<T>(
|
|||||||
Some((value, monitor))
|
Some((value, monitor))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "flutter")]
|
|
||||||
fn cursor_monitor(
|
fn cursor_monitor(
|
||||||
display: usize,
|
display: usize,
|
||||||
state: &ProbeState,
|
state: &ProbeState,
|
||||||
@@ -2332,7 +2312,6 @@ mod drm_capturer_tests {
|
|||||||
assert!(m2[0].is_none() && m2[1].is_none());
|
assert!(m2[0].is_none() && m2[1].is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "flutter")]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn cursor_monitor_reserves_other_displays_before_guessing_density() {
|
fn cursor_monitor_reserves_other_displays_before_guessing_density() {
|
||||||
let state = ProbeState::Available(
|
let state = ProbeState::Available(
|
||||||
|
|||||||
Reference in New Issue
Block a user