fix: wayland controlled side, cursor misalignment (#13537)
Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
@@ -1755,6 +1755,13 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
thread.video_sender.send(MediaData::Reset).ok();
|
||||
}
|
||||
|
||||
let mut scale = 1.0;
|
||||
if let Some(pi) = &self.handler.lc.read().unwrap().peer_info {
|
||||
if let Some(d) = pi.displays.get(s.display as usize) {
|
||||
scale = d.scale;
|
||||
}
|
||||
}
|
||||
|
||||
if s.width > 0 && s.height > 0 {
|
||||
self.handler.set_display(
|
||||
s.x,
|
||||
@@ -1762,6 +1769,7 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
s.width,
|
||||
s.height,
|
||||
s.cursor_embedded,
|
||||
scale,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,17 +427,8 @@ impl ClipboardContext {
|
||||
// Don't use `hbb_common::platform::linux::is_kde()` here.
|
||||
// It's not correct in the server process.
|
||||
#[cfg(target_os = "linux")]
|
||||
let is_kde_x11 = {
|
||||
use hbb_common::platform::linux::CMD_SH;
|
||||
let is_kde = std::process::Command::new(CMD_SH.as_str())
|
||||
.arg("-c")
|
||||
.arg("ps -e | grep -E kded[0-9]+ | grep -v grep")
|
||||
.stdout(std::process::Stdio::piped())
|
||||
.output()
|
||||
.map(|o| !o.stdout.is_empty())
|
||||
.unwrap_or(false);
|
||||
is_kde && crate::platform::linux::is_x11()
|
||||
};
|
||||
let is_kde_x11 = hbb_common::platform::linux::is_kde_session()
|
||||
&& crate::platform::linux::is_x11();
|
||||
#[cfg(target_os = "macos")]
|
||||
let is_kde_x11 = false;
|
||||
let clear_holder_text = if is_kde_x11 {
|
||||
|
||||
@@ -609,7 +609,22 @@ impl FlutterHandler {
|
||||
h.insert("original_width", original_resolution.width);
|
||||
h.insert("original_height", original_resolution.height);
|
||||
}
|
||||
h.insert("scale", (d.scale * 100.0f64) as i32);
|
||||
// Don't convert scale (x 100) to i32 directly.
|
||||
// (d.scale * 100.0f64) as i32 may produces inaccuracies.
|
||||
//
|
||||
// Example: GNOME Wayland with Fractional Scaling enabled:
|
||||
// - Physical resolution: 2560x1600
|
||||
// - Logical resolution: 1074x1065
|
||||
// - Scale factor: 150%
|
||||
// Passing physical dimensions and scale factor prevents accurate logical resolution calculation
|
||||
// since 2560/1.5 = 1706.666... (rounded to 1706.67) and 1600/1.5 = 1066.666... (rounded to 1066.67)
|
||||
// h.insert("scale", (d.scale * 100.0f64) as i32);
|
||||
|
||||
// Send scaled_width for accurate logical scale calculation.
|
||||
if d.scale > 0.0 {
|
||||
let scaled_width = (d.width as f64 / d.scale).round() as i32;
|
||||
h.insert("scaled_width", scaled_width);
|
||||
}
|
||||
msg_vec.push(h);
|
||||
}
|
||||
serde_json::ser::to_string(&msg_vec).unwrap_or("".to_owned())
|
||||
@@ -679,7 +694,7 @@ impl InvokeUiSession for FlutterHandler {
|
||||
}
|
||||
|
||||
/// unused in flutter, use switch_display or set_peer_info
|
||||
fn set_display(&self, _x: i32, _y: i32, _w: i32, _h: i32, _cursor_embedded: bool) {}
|
||||
fn set_display(&self, _x: i32, _y: i32, _w: i32, _h: i32, _cursor_embedded: bool, _scale: f64) {}
|
||||
|
||||
fn update_privacy_mode(&self) {
|
||||
self.push_event::<&str>("update_privacy_mode", &[], &[]);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
use crate::keyboard::input_source::{change_input_source, get_cur_session_input_source};
|
||||
#[cfg(target_os = "linux")]
|
||||
use crate::platform::linux::is_x11;
|
||||
use crate::{
|
||||
client::file_trait::FileManager,
|
||||
common::{make_fd_to_json, make_vec_fd_to_json},
|
||||
@@ -1471,19 +1473,45 @@ pub fn main_get_main_display() -> SyncReturn<String> {
|
||||
#[cfg(not(target_os = "ios"))]
|
||||
let mut display_info = "".to_owned();
|
||||
#[cfg(not(target_os = "ios"))]
|
||||
if let Ok(displays) = crate::display_service::try_get_displays() {
|
||||
// to-do: Need to detect current display index.
|
||||
if let Some(display) = displays.iter().next() {
|
||||
display_info = serde_json::to_string(&HashMap::from([
|
||||
("w", display.width()),
|
||||
("h", display.height()),
|
||||
]))
|
||||
.unwrap_or_default();
|
||||
{
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
let is_linux_wayland = false;
|
||||
#[cfg(target_os = "linux")]
|
||||
let is_linux_wayland = !is_x11();
|
||||
|
||||
if !is_linux_wayland {
|
||||
if let Ok(displays) = crate::display_service::try_get_displays() {
|
||||
// to-do: Need to detect current display index.
|
||||
if let Some(display) = displays.iter().next() {
|
||||
display_info = serde_json::to_string(&HashMap::from([
|
||||
("w", display.width()),
|
||||
("h", display.height()),
|
||||
]))
|
||||
.unwrap_or_default();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
if is_linux_wayland {
|
||||
let displays = scrap::wayland::display::get_displays();
|
||||
if let Some(display) = displays.displays.get(displays.primary) {
|
||||
let logical_size = display
|
||||
.logical_size
|
||||
.unwrap_or((display.width, display.height));
|
||||
display_info = serde_json::to_string(&HashMap::from([
|
||||
("w", logical_size.0),
|
||||
("h", logical_size.1),
|
||||
]))
|
||||
.unwrap_or_default();
|
||||
}
|
||||
}
|
||||
}
|
||||
SyncReturn(display_info)
|
||||
}
|
||||
|
||||
// No need to check if is on Wayland in this function.
|
||||
// The Flutter side gets display information on Wayland using a different method.
|
||||
pub fn main_get_displays() -> SyncReturn<String> {
|
||||
#[cfg(target_os = "ios")]
|
||||
let display_info = "".to_owned();
|
||||
|
||||
@@ -304,6 +304,12 @@ pub(super) fn get_display_info(idx: usize) -> Option<DisplayInfo> {
|
||||
// Display to DisplayInfo
|
||||
// The DisplayInfo is be sent to the peer.
|
||||
pub(super) fn check_update_displays(all: &Vec<Display>) {
|
||||
// For compatibility: if only one display, scale remains 1.0 and we use the physical size for `uinput`.
|
||||
// If there are multiple displays, we use the logical size for `uinput` by setting scale to d.scale().
|
||||
#[cfg(target_os = "linux")]
|
||||
let use_logical_scale = !is_x11()
|
||||
&& crate::is_server()
|
||||
&& scrap::wayland::display::get_displays().displays.len() > 1;
|
||||
let displays = all
|
||||
.iter()
|
||||
.map(|d| {
|
||||
@@ -315,6 +321,12 @@ pub(super) fn check_update_displays(all: &Vec<Display>) {
|
||||
{
|
||||
scale = d.scale();
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
if use_logical_scale {
|
||||
scale = d.scale();
|
||||
}
|
||||
}
|
||||
let original_resolution = get_original_resolution(
|
||||
&display_name,
|
||||
((d.width() as f64) / scale).round() as usize,
|
||||
|
||||
@@ -20,7 +20,10 @@ use scrap::wayland::pipewire::RDP_SESSION_INFO;
|
||||
use std::{
|
||||
convert::TryFrom,
|
||||
ops::{Deref, DerefMut},
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
mpsc,
|
||||
},
|
||||
thread,
|
||||
time::{self, Duration, Instant},
|
||||
};
|
||||
@@ -1834,6 +1837,51 @@ pub fn wayland_use_rdp_input() -> bool {
|
||||
!crate::platform::is_x11() && !crate::is_server()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub struct TemporaryMouseMoveHandle {
|
||||
thread_handle: Option<std::thread::JoinHandle<()>>,
|
||||
tx: Option<mpsc::Sender<(i32, i32)>>,
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
impl TemporaryMouseMoveHandle {
|
||||
pub fn new() -> Self {
|
||||
let (tx, rx) = mpsc::channel::<(i32, i32)>();
|
||||
let thread_handle = std::thread::spawn(move || {
|
||||
log::debug!("TemporaryMouseMoveHandle thread started");
|
||||
for (x, y) in rx {
|
||||
ENIGO.lock().unwrap().mouse_move_to(x, y);
|
||||
}
|
||||
log::debug!("TemporaryMouseMoveHandle thread exiting");
|
||||
});
|
||||
TemporaryMouseMoveHandle {
|
||||
thread_handle: Some(thread_handle),
|
||||
tx: Some(tx),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn move_mouse_to(&self, x: i32, y: i32) {
|
||||
if let Some(tx) = &self.tx {
|
||||
let _ = tx.send((x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
impl Drop for TemporaryMouseMoveHandle {
|
||||
fn drop(&mut self) {
|
||||
log::debug!("Dropping TemporaryMouseMoveHandle");
|
||||
// Close the channel to signal the thread to exit.
|
||||
self.tx.take();
|
||||
// Wait for the thread to finish.
|
||||
if let Some(thread_handle) = self.thread_handle.take() {
|
||||
if let Err(e) = thread_handle.join() {
|
||||
log::error!("Error joining TemporaryMouseMoveHandle thread: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref MODIFIER_MAP: HashMap<i32, Key> = [
|
||||
(ControlKey::Alt, Key::Alt),
|
||||
|
||||
@@ -71,6 +71,7 @@ pub mod client {
|
||||
stream: PwStreamInfo,
|
||||
resolution: (usize, usize),
|
||||
scale: Option<f64>,
|
||||
position: (f64, f64),
|
||||
}
|
||||
|
||||
impl RdpInputMouse {
|
||||
@@ -98,12 +99,14 @@ pub mod client {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let pos = stream.get_position();
|
||||
Ok(Self {
|
||||
conn,
|
||||
session,
|
||||
stream,
|
||||
resolution,
|
||||
scale,
|
||||
position: (pos.0 as f64, pos.1 as f64),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -128,6 +131,8 @@ pub mod client {
|
||||
} else {
|
||||
y as f64
|
||||
};
|
||||
let x = x - self.position.0;
|
||||
let y = y - self.position.1;
|
||||
let portal = get_portal(&self.conn);
|
||||
let _ = remote_desktop_portal::notify_pointer_motion_absolute(
|
||||
&portal,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use super::*;
|
||||
use hbb_common::{
|
||||
allow_err,
|
||||
platform::linux::{CMD_SH, DISTRO},
|
||||
use hbb_common::{allow_err, anyhow, platform::linux::DISTRO};
|
||||
use scrap::{
|
||||
is_cursor_embedded, set_map_err,
|
||||
wayland::pipewire::{fill_displays, try_fix_logical_size},
|
||||
Capturer, Display, Frame, TraitCapturer,
|
||||
};
|
||||
use scrap::{is_cursor_embedded, set_map_err, Capturer, Display, Frame, TraitCapturer};
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::process::{Command, Output};
|
||||
|
||||
use crate::{
|
||||
client::{
|
||||
@@ -127,45 +127,28 @@ pub(super) fn is_inited() -> Option<Message> {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_max_desktop_resolution() -> Option<String> {
|
||||
// works with Xwayland
|
||||
let output: Output = Command::new(CMD_SH.as_str())
|
||||
.arg("-c")
|
||||
.arg("xrandr | awk '/current/ { print $8,$9,$10 }'")
|
||||
.output()
|
||||
.ok()?;
|
||||
|
||||
if output.status.success() {
|
||||
let result = String::from_utf8_lossy(&output.stdout);
|
||||
Some(result.trim().to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate_max_resolution_from_displays(displays: &[Display]) -> (i32, i32) {
|
||||
// TODO: this doesn't work in most situations other than sharing all displays
|
||||
// this is because the function only gets called with the displays being shared with pipewire
|
||||
// the xrandr method does work otherwise we could get this correctly using xdg-output-unstable-v1 when xrandr isn't available
|
||||
// log::warn!("using incorrect max resolution calculation uinput may not work correctly");
|
||||
let (mut max_x, mut max_y) = (0, 0);
|
||||
for d in displays {
|
||||
let (x, y) = d.origin();
|
||||
max_x = max_x.max(x + d.width() as i32);
|
||||
max_y = max_y.max(y + d.height() as i32);
|
||||
}
|
||||
(max_x, max_y)
|
||||
}
|
||||
|
||||
pub(super) async fn check_init() -> ResultType<()> {
|
||||
if !is_x11() {
|
||||
let mut minx = 0;
|
||||
let mut maxx = 0;
|
||||
let mut miny = 0;
|
||||
let mut maxy = 0;
|
||||
let use_uinput = crate::input_service::wayland_use_uinput();
|
||||
|
||||
if CAP_DISPLAY_INFO.read().unwrap().is_empty() {
|
||||
if crate::input_service::wayland_use_uinput() {
|
||||
if let Some((minx, maxx, miny, maxy)) =
|
||||
scrap::wayland::display::get_desktop_rect_for_uinput()
|
||||
{
|
||||
log::info!(
|
||||
"update mouse resolution: ({}, {}), ({}, {})",
|
||||
minx,
|
||||
maxx,
|
||||
miny,
|
||||
maxy
|
||||
);
|
||||
allow_err!(
|
||||
input_service::update_mouse_resolution(minx, maxx, miny, maxy).await
|
||||
);
|
||||
} else {
|
||||
log::warn!("Failed to get desktop rect for uinput");
|
||||
}
|
||||
}
|
||||
|
||||
let mut lock = CAP_DISPLAY_INFO.write().unwrap();
|
||||
if lock.is_empty() {
|
||||
// Check if PipeWire is already initialized to prevent duplicate recorder creation
|
||||
@@ -173,8 +156,16 @@ pub(super) async fn check_init() -> ResultType<()> {
|
||||
log::warn!("wayland_diag: Preventing duplicate PipeWire initialization");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let all = Display::all()?;
|
||||
|
||||
let mut all = Display::all()?;
|
||||
log::debug!("Initializing displays with fill_displays()");
|
||||
{
|
||||
let temp_mouse_move_handle = input_service::TemporaryMouseMoveHandle::new();
|
||||
let move_mouse_to = |x, y| temp_mouse_move_handle.move_mouse_to(x, y);
|
||||
fill_displays(move_mouse_to, crate::get_cursor_pos, &mut all)?;
|
||||
}
|
||||
log::debug!("Attempting to fix logical size with try_fix_logical_size()");
|
||||
try_fix_logical_size(&mut all);
|
||||
*PIPEWIRE_INITIALIZED.write().unwrap() = true;
|
||||
let num = all.len();
|
||||
let primary = super::display_service::get_primary_2(&all);
|
||||
@@ -189,40 +180,23 @@ pub(super) async fn check_init() -> ResultType<()> {
|
||||
rects.push((d.origin(), d.width(), d.height()));
|
||||
}
|
||||
|
||||
log::debug!("#displays={}, primary={}, rects: {:?}, cpus={}/{}", num, primary, rects, num_cpus::get_physical(), num_cpus::get());
|
||||
|
||||
if use_uinput {
|
||||
let (max_width, max_height) = match get_max_desktop_resolution() {
|
||||
Some(result) if !result.is_empty() => {
|
||||
let resolution: Vec<&str> = result.split(" ").collect();
|
||||
if let (Ok(w), Ok(h)) = (
|
||||
resolution[0].parse::<i32>(),
|
||||
resolution.get(2)
|
||||
.unwrap_or(&"0")
|
||||
.trim_end_matches(",")
|
||||
.parse::<i32>()
|
||||
) {
|
||||
(w, h)
|
||||
} else {
|
||||
calculate_max_resolution_from_displays(&all)
|
||||
}
|
||||
}
|
||||
_ => calculate_max_resolution_from_displays(&all),
|
||||
};
|
||||
|
||||
minx = 0;
|
||||
maxx = max_width;
|
||||
miny = 0;
|
||||
maxy = max_height;
|
||||
}
|
||||
log::debug!(
|
||||
"#displays={}, primary={}, rects: {:?}, cpus={}/{}",
|
||||
num,
|
||||
primary,
|
||||
rects,
|
||||
num_cpus::get_physical(),
|
||||
num_cpus::get()
|
||||
);
|
||||
|
||||
// Create individual CapDisplayInfo for each display with its own capturer
|
||||
for (idx, display) in all.into_iter().enumerate() {
|
||||
let capturer = Box::into_raw(Box::new(
|
||||
Capturer::new(display).with_context(|| format!("Failed to create capturer for display {}", idx))?,
|
||||
));
|
||||
let capturer =
|
||||
Box::into_raw(Box::new(Capturer::new(display).with_context(|| {
|
||||
format!("Failed to create capturer for display {}", idx)
|
||||
})?));
|
||||
let capturer = CapturerPtr(capturer);
|
||||
|
||||
|
||||
let cap_display_info = Box::into_raw(Box::new(CapDisplayInfo {
|
||||
rects: rects.clone(),
|
||||
displays: displays.clone(),
|
||||
@@ -231,24 +205,11 @@ pub(super) async fn check_init() -> ResultType<()> {
|
||||
current: idx,
|
||||
capturer,
|
||||
}));
|
||||
|
||||
|
||||
lock.insert(idx, cap_display_info as u64);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if use_uinput {
|
||||
if minx != maxx && miny != maxy {
|
||||
log::info!(
|
||||
"update mouse resolution: ({}, {}), ({}, {})",
|
||||
minx,
|
||||
maxx,
|
||||
miny,
|
||||
maxy
|
||||
);
|
||||
allow_err!(input_service::update_mouse_resolution(minx, maxx, miny, maxy).await);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -293,12 +254,14 @@ pub fn clear() {
|
||||
}
|
||||
}
|
||||
write_lock.clear();
|
||||
|
||||
|
||||
// Reset PipeWire initialization flag to allow recreation on next init
|
||||
*PIPEWIRE_INITIALIZED.write().unwrap() = false;
|
||||
}
|
||||
|
||||
pub(super) fn get_capturer_for_display(display_idx: usize) -> ResultType<super::video_service::CapturerInfo> {
|
||||
pub(super) fn get_capturer_for_display(
|
||||
display_idx: usize,
|
||||
) -> ResultType<super::video_service::CapturerInfo> {
|
||||
if is_x11() {
|
||||
bail!("Do not call this function if not wayland");
|
||||
}
|
||||
@@ -307,7 +270,7 @@ pub(super) fn get_capturer_for_display(display_idx: usize) -> ResultType<super::
|
||||
let cap_display_info: *const CapDisplayInfo = *addr as _;
|
||||
unsafe {
|
||||
let cap_display_info = &*cap_display_info;
|
||||
let rect = cap_display_info.rects[cap_display_info.current];
|
||||
let rect = cap_display_info.rects[cap_display_info.current];
|
||||
Ok(super::video_service::CapturerInfo {
|
||||
origin: rect.0,
|
||||
width: rect.1,
|
||||
@@ -320,7 +283,10 @@ pub(super) fn get_capturer_for_display(display_idx: usize) -> ResultType<super::
|
||||
})
|
||||
}
|
||||
} else {
|
||||
bail!("Failed to get capturer display info for display {}", display_idx);
|
||||
bail!(
|
||||
"Failed to get capturer display info for display {}",
|
||||
display_idx
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@ function isEnterKey(evt) {
|
||||
|
||||
function getScaleFactor() {
|
||||
if (!is_win) return 1;
|
||||
return self.toPixels(10000dip) / 10000.;
|
||||
var s = self.toPixels(10000dip) / 10000.;
|
||||
return s < 0.000001 ? 1 : s;
|
||||
}
|
||||
var scaleFactor = getScaleFactor();
|
||||
view << event resolutionchange {
|
||||
|
||||
@@ -125,8 +125,9 @@ impl InvokeUiSession for SciterHandler {
|
||||
}
|
||||
}
|
||||
|
||||
fn set_display(&self, x: i32, y: i32, w: i32, h: i32, cursor_embedded: bool) {
|
||||
self.call("setDisplay", &make_args!(x, y, w, h, cursor_embedded));
|
||||
fn set_display(&self, x: i32, y: i32, w: i32, h: i32, cursor_embedded: bool, scale: f64) {
|
||||
let scale = if scale <= 0.0 { 1.0 } else { scale };
|
||||
self.call("setDisplay", &make_args!(x, y, w, h, cursor_embedded, scale));
|
||||
// https://sciter.com/forums/topic/color_spaceiyuv-crash
|
||||
// Nothing spectacular in decoder – done on CPU side.
|
||||
// So if you can do BGRA translation on your side – the better.
|
||||
|
||||
@@ -4,10 +4,13 @@ var is_port_forward = handler.is_port_forward();
|
||||
var input_blocked = false;
|
||||
var display_width = 0;
|
||||
var display_height = 0;
|
||||
var display_remote_scale = 1;
|
||||
var display_origin_x = 0;
|
||||
var display_origin_y = 0;
|
||||
var display_cursor_embedded = false;
|
||||
var display_scale = 1;
|
||||
// the scale factor is different from `display_scale` if peer platform is Linux (Wayland).
|
||||
var cursor_scale = 1;
|
||||
var keyboard_enabled = true; // server side
|
||||
var clipboard_enabled = true; // server side
|
||||
var audio_enabled = true; // server side
|
||||
@@ -15,13 +18,15 @@ var file_enabled = true; // server side
|
||||
var restart_enabled = true; // server side
|
||||
var recording_enabled = true; // server side
|
||||
var scroll_body = $(body);
|
||||
var peer_platform = "";
|
||||
|
||||
handler.setDisplay = function(x, y, w, h, cursor_embedded) {
|
||||
handler.setDisplay = function(x, y, w, h, cursor_embedded, scale) {
|
||||
display_width = w;
|
||||
display_height = h;
|
||||
display_origin_x = x;
|
||||
display_origin_y = y;
|
||||
display_cursor_embedded = cursor_embedded;
|
||||
display_remote_scale = scale;
|
||||
adaptDisplay();
|
||||
if (recording) handler.record_screen(true, 0, w, h);
|
||||
}
|
||||
@@ -29,12 +34,24 @@ handler.setDisplay = function(x, y, w, h, cursor_embedded) {
|
||||
// in case toolbar not shown correctly
|
||||
view.windowMinSize = (scaleIt(500), scaleIt(300));
|
||||
|
||||
function get_peer_platform() {
|
||||
if (peer_platform == "") {
|
||||
peer_platform = handler.peer_platform();
|
||||
}
|
||||
return peer_platform;
|
||||
}
|
||||
|
||||
function isRemoteLinux() {
|
||||
return get_peer_platform() == "Linux";
|
||||
}
|
||||
|
||||
function adaptDisplay() {
|
||||
var w = display_width;
|
||||
var h = display_height;
|
||||
if (!w || !h) return;
|
||||
var style = handler.get_view_style();
|
||||
display_scale = 1.;
|
||||
cursor_scale = 1.;
|
||||
var (sx, sy, sw, sh) = view.screenBox(view.windowState == View.WINDOW_FULL_SCREEN ? #frame : #workarea, #rectw);
|
||||
if (sw >= w && sh > h) {
|
||||
var hh = $(header).box(#height, #border);
|
||||
@@ -71,6 +88,10 @@ function adaptDisplay() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isRemoteLinux()) {
|
||||
cursor_scale = display_scale * display_remote_scale;
|
||||
if (cursor_scale <= 0.0001) cursor_scale = 1.;
|
||||
}
|
||||
refreshCursor();
|
||||
handler.style.set {
|
||||
width: w / scaleFactor + "px",
|
||||
@@ -279,7 +300,7 @@ function handler.onMouse(evt)
|
||||
entered = false;
|
||||
stdout.println("leave");
|
||||
handler.leave(handler.get_keyboard_mode());
|
||||
if (is_left_down && handler.peer_platform() == "Android") {
|
||||
if (is_left_down && get_peer_platform() == "Android") {
|
||||
is_left_down = false;
|
||||
handler.send_mouse((1 << 3) | 2, 0, 0, evt.altKey,
|
||||
evt.ctrlKey, evt.shiftKey, evt.commandKey);
|
||||
@@ -303,8 +324,8 @@ function handler.onMouse(evt)
|
||||
resetWheel();
|
||||
}
|
||||
if (!keyboard_enabled) return false;
|
||||
x = (x / display_scale).toInteger();
|
||||
y = (y / display_scale).toInteger();
|
||||
x = (x / cursor_scale).toInteger();
|
||||
y = (y / cursor_scale).toInteger();
|
||||
// insert down between two up, osx has this behavior for triple click
|
||||
if (last_mouse_mask == 2 && mask == 2) {
|
||||
handler.send_mouse((evt.buttons << 3) | 1, 0, 0, evt.altKey,
|
||||
@@ -339,14 +360,18 @@ var cursors = {};
|
||||
var image_binded;
|
||||
|
||||
function scaleCursorImage(img) {
|
||||
var w = (img.width * display_scale).toInteger();
|
||||
var h = (img.height * display_scale).toInteger();
|
||||
var factor = cursor_scale;
|
||||
if (cursor_img.style#display != 'none') {
|
||||
factor /= scaleFactor;
|
||||
}
|
||||
var w = (img.width * factor).toInteger();
|
||||
var h = (img.height * factor).toInteger();
|
||||
cursor_img.style.set {
|
||||
width: w + "px",
|
||||
height: h + "px",
|
||||
};
|
||||
self.bindImage("in-memory:cursor", img);
|
||||
if (display_scale == 1) return img;
|
||||
if (factor == 1) return img;
|
||||
function paint(gfx) {
|
||||
gfx.drawImage(img, 0, 0, w, h);
|
||||
}
|
||||
@@ -360,7 +385,7 @@ function updateCursor(system=false) {
|
||||
if (system) {
|
||||
handler.style#cursor = undefined;
|
||||
} else if (cur_img) {
|
||||
handler.style.cursor(cur_img, (cur_hotx * display_scale).toInteger(), (cur_hoty * display_scale).toInteger());
|
||||
handler.style.cursor(cur_img, (cur_hotx * cursor_scale).toInteger(), (cur_hoty * cursor_scale).toInteger());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,14 +438,15 @@ handler.setCursorPosition = function(x, y) {
|
||||
cur_y = y - display_origin_y;
|
||||
var x = cur_x - cur_hotx;
|
||||
var y = cur_y - cur_hoty;
|
||||
x *= display_scale / scaleFactor;
|
||||
y *= display_scale / scaleFactor;
|
||||
x *= cursor_scale / scaleFactor;
|
||||
y *= cursor_scale / scaleFactor;
|
||||
cursor_img.style.set {
|
||||
left: x + "px",
|
||||
top: y + "px",
|
||||
};
|
||||
if (cursor_img.style#display == 'none') {
|
||||
cursor_img.style#display = "block";
|
||||
refreshCursor();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1658,7 +1658,7 @@ pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default {
|
||||
fn set_cursor_data(&self, cd: CursorData);
|
||||
fn set_cursor_id(&self, id: String);
|
||||
fn set_cursor_position(&self, cp: CursorPosition);
|
||||
fn set_display(&self, x: i32, y: i32, w: i32, h: i32, cursor_embedded: bool);
|
||||
fn set_display(&self, x: i32, y: i32, w: i32, h: i32, cursor_embedded: bool, scale: f64);
|
||||
fn switch_display(&self, display: &SwitchDisplay);
|
||||
fn set_peer_info(&self, peer_info: &PeerInfo); // flutter
|
||||
fn set_displays(&self, displays: &Vec<DisplayInfo>);
|
||||
@@ -1804,6 +1804,7 @@ impl<T: InvokeUiSession> Interface for Session<T> {
|
||||
current.width,
|
||||
current.height,
|
||||
current.cursor_embedded,
|
||||
current.scale,
|
||||
);
|
||||
}
|
||||
self.update_privacy_mode();
|
||||
|
||||
Reference in New Issue
Block a user