mirror of
https://github.com/rustdesk/rustdesk.git
synced 2025-06-07 18:02:48 +08:00
enable retina scale factor (#7269)
* enable retina scale factor * enabled only when there are only one video service running * scale mouse event * scale cursor position * scale remote menu display button * adjust resolution Signed-off-by: 21pages <pages21@163.com> * Update server.rs --------- Signed-off-by: 21pages <pages21@163.com> Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
This commit is contained in:
parent
96792bec78
commit
50d080d098
@ -759,15 +759,18 @@ class _MonitorMenu extends StatelessWidget {
|
|||||||
final children = <Widget>[];
|
final children = <Widget>[];
|
||||||
for (var i = 0; i < pi.displays.length; i++) {
|
for (var i = 0; i < pi.displays.length; i++) {
|
||||||
final d = pi.displays[i];
|
final d = pi.displays[i];
|
||||||
final fontSize = (d.width * scale < d.height * scale
|
double s = d.scale;
|
||||||
? d.width * scale
|
int dWidth = d.width.toDouble() ~/ s;
|
||||||
: d.height * scale) *
|
int dHeight = d.height.toDouble() ~/ s;
|
||||||
|
final fontSize = (dWidth * scale < dHeight * scale
|
||||||
|
? dWidth * scale
|
||||||
|
: dHeight * scale) *
|
||||||
0.65;
|
0.65;
|
||||||
children.add(Positioned(
|
children.add(Positioned(
|
||||||
left: (d.x - rect.left) * scale + startX,
|
left: (d.x - rect.left) * scale + startX,
|
||||||
top: (d.y - rect.top) * scale + startY,
|
top: (d.y - rect.top) * scale + startY,
|
||||||
width: d.width * scale,
|
width: dWidth * scale,
|
||||||
height: d.height * scale,
|
height: dHeight * scale,
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
@ -1287,7 +1290,9 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
|
|||||||
if (lastGroupValue == _kCustomResolutionValue) {
|
if (lastGroupValue == _kCustomResolutionValue) {
|
||||||
_groupValue = _kCustomResolutionValue;
|
_groupValue = _kCustomResolutionValue;
|
||||||
} else {
|
} else {
|
||||||
_groupValue = '${rect?.width.toInt()}x${rect?.height.toInt()}';
|
var scale = pi.scaleOfDisplay(pi.currentDisplay);
|
||||||
|
_groupValue =
|
||||||
|
'${(rect?.width ?? 0) ~/ scale}x${(rect?.height ?? 0) ~/ scale}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1386,6 +1391,11 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
|
|||||||
if (display == null) {
|
if (display == null) {
|
||||||
return Offstage();
|
return Offstage();
|
||||||
}
|
}
|
||||||
|
if (!resolutions.any((e) =>
|
||||||
|
e.width == display.originalWidth &&
|
||||||
|
e.height == display.originalHeight)) {
|
||||||
|
return Offstage();
|
||||||
|
}
|
||||||
return Offstage(
|
return Offstage(
|
||||||
offstage: !showOriginalBtn,
|
offstage: !showOriginalBtn,
|
||||||
child: MenuButton(
|
child: MenuButton(
|
||||||
|
@ -138,21 +138,29 @@ class FfiModel with ChangeNotifier {
|
|||||||
sessionId = parent.target!.sessionId;
|
sessionId = parent.target!.sessionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rect? globalDisplaysRect() => _getDisplaysRect(_pi.displays);
|
Rect? globalDisplaysRect() => _getDisplaysRect(_pi.displays, true);
|
||||||
Rect? displaysRect() => _getDisplaysRect(_pi.getCurDisplays());
|
Rect? displaysRect() => _getDisplaysRect(_pi.getCurDisplays(), false);
|
||||||
Rect? _getDisplaysRect(List<Display> displays) {
|
Rect? _getDisplaysRect(List<Display> displays, bool useDisplayScale) {
|
||||||
if (displays.isEmpty) {
|
if (displays.isEmpty) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
int scale(int len, double s) {
|
||||||
|
if (useDisplayScale) {
|
||||||
|
return len.toDouble() ~/ s;
|
||||||
|
} else {
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
double l = displays[0].x;
|
double l = displays[0].x;
|
||||||
double t = displays[0].y;
|
double t = displays[0].y;
|
||||||
double r = displays[0].x + displays[0].width;
|
double r = displays[0].x + scale(displays[0].width, displays[0].scale);
|
||||||
double b = displays[0].y + displays[0].height;
|
double b = displays[0].y + scale(displays[0].height, displays[0].scale);
|
||||||
for (var display in displays.sublist(1)) {
|
for (var display in displays.sublist(1)) {
|
||||||
l = min(l, display.x);
|
l = min(l, display.x);
|
||||||
t = min(t, display.y);
|
t = min(t, display.y);
|
||||||
r = max(r, display.x + display.width);
|
r = max(r, display.x + scale(display.width, display.scale));
|
||||||
b = max(b, display.y + display.height);
|
b = max(b, display.y + scale(display.height, display.scale));
|
||||||
}
|
}
|
||||||
return Rect.fromLTRB(l, t, r, b);
|
return Rect.fromLTRB(l, t, r, b);
|
||||||
}
|
}
|
||||||
@ -476,6 +484,7 @@ class FfiModel with ChangeNotifier {
|
|||||||
int.tryParse(evt['original_width']) ?? kInvalidResolutionValue;
|
int.tryParse(evt['original_width']) ?? kInvalidResolutionValue;
|
||||||
newDisplay.originalHeight =
|
newDisplay.originalHeight =
|
||||||
int.tryParse(evt['original_height']) ?? kInvalidResolutionValue;
|
int.tryParse(evt['original_height']) ?? kInvalidResolutionValue;
|
||||||
|
newDisplay._scale = _pi.scaleOfDisplay(display);
|
||||||
_pi.displays[display] = newDisplay;
|
_pi.displays[display] = newDisplay;
|
||||||
|
|
||||||
if (!_pi.isSupportMultiUiSession || _pi.currentDisplay == display) {
|
if (!_pi.isSupportMultiUiSession || _pi.currentDisplay == display) {
|
||||||
@ -890,6 +899,8 @@ class FfiModel with ChangeNotifier {
|
|||||||
d.cursorEmbedded = evt['cursor_embedded'] == 1;
|
d.cursorEmbedded = evt['cursor_embedded'] == 1;
|
||||||
d.originalWidth = evt['original_width'] ?? kInvalidResolutionValue;
|
d.originalWidth = evt['original_width'] ?? kInvalidResolutionValue;
|
||||||
d.originalHeight = evt['original_height'] ?? kInvalidResolutionValue;
|
d.originalHeight = evt['original_height'] ?? kInvalidResolutionValue;
|
||||||
|
double v = (evt['scale']?.toDouble() ?? 100.0) / 100;
|
||||||
|
d._scale = v > 1.0 ? v : 1.0;
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2384,6 +2395,8 @@ class Display {
|
|||||||
bool cursorEmbedded = false;
|
bool cursorEmbedded = false;
|
||||||
int originalWidth = kInvalidResolutionValue;
|
int originalWidth = kInvalidResolutionValue;
|
||||||
int originalHeight = kInvalidResolutionValue;
|
int originalHeight = kInvalidResolutionValue;
|
||||||
|
double _scale = 1.0;
|
||||||
|
double get scale => _scale > 1.0 ? _scale : 1.0;
|
||||||
|
|
||||||
Display() {
|
Display() {
|
||||||
width = (isDesktop || isWebDesktop)
|
width = (isDesktop || isWebDesktop)
|
||||||
@ -2503,6 +2516,13 @@ class PeerInfo with ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double scaleOfDisplay(int display) {
|
||||||
|
if (display >= 0 && display < displays.length) {
|
||||||
|
return displays[display].scale;
|
||||||
|
}
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const canvasKey = 'canvas';
|
const canvasKey = 'canvas';
|
||||||
|
@ -49,6 +49,7 @@ message DisplayInfo {
|
|||||||
bool online = 6;
|
bool online = 6;
|
||||||
bool cursor_embedded = 7;
|
bool cursor_embedded = 7;
|
||||||
Resolution original_resolution = 8;
|
Resolution original_resolution = 8;
|
||||||
|
double scale = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
message PortForward {
|
message PortForward {
|
||||||
|
@ -128,6 +128,10 @@ impl Display {
|
|||||||
self.0.height()
|
self.0.height()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn scale(&self) -> f64 {
|
||||||
|
self.0.scale()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> String {
|
pub fn name(&self) -> String {
|
||||||
self.0.id().to_string()
|
self.0.id().to_string()
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ impl Display {
|
|||||||
let w = unsafe { CGDisplayPixelsWide(self.0) };
|
let w = unsafe { CGDisplayPixelsWide(self.0) };
|
||||||
let s = self.scale();
|
let s = self.scale();
|
||||||
if s > 1.0 {
|
if s > 1.0 {
|
||||||
((w as f64) * s).round() as usize
|
((w as f64) * s).round() as usize
|
||||||
} else {
|
} else {
|
||||||
w
|
w
|
||||||
}
|
}
|
||||||
@ -48,7 +48,7 @@ impl Display {
|
|||||||
let h = unsafe { CGDisplayPixelsHigh(self.0) };
|
let h = unsafe { CGDisplayPixelsHigh(self.0) };
|
||||||
let s = self.scale();
|
let s = self.scale();
|
||||||
if s > 1.0 {
|
if s > 1.0 {
|
||||||
((h as f64) * s).round() as usize
|
((h as f64) * s).round() as usize
|
||||||
} else {
|
} else {
|
||||||
h
|
h
|
||||||
}
|
}
|
||||||
@ -71,7 +71,13 @@ impl Display {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn scale(self) -> f64 {
|
pub fn scale(self) -> f64 {
|
||||||
// unsafe { BackingScaleFactor() as _ }
|
let s = unsafe { BackingScaleFactor() as _ };
|
||||||
|
if s > 1. {
|
||||||
|
let enable_retina = super::ENABLE_RETINA.lock().unwrap().clone();
|
||||||
|
if enable_retina {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
1.
|
1.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,3 +9,9 @@ mod config;
|
|||||||
mod display;
|
mod display;
|
||||||
pub mod ffi;
|
pub mod ffi;
|
||||||
mod frame;
|
mod frame;
|
||||||
|
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
pub static ref ENABLE_RETINA: Arc<Mutex<bool>> = Arc::new(Mutex::new(true));
|
||||||
|
}
|
||||||
|
@ -512,6 +512,7 @@ impl FlutterHandler {
|
|||||||
h.insert("original_width", original_resolution.width);
|
h.insert("original_width", original_resolution.width);
|
||||||
h.insert("original_height", original_resolution.height);
|
h.insert("original_height", original_resolution.height);
|
||||||
}
|
}
|
||||||
|
h.insert("scale", (d.scale * 100.0f64) as i32);
|
||||||
msg_vec.push(h);
|
msg_vec.push(h);
|
||||||
}
|
}
|
||||||
serde_json::ser::to_string(&msg_vec).unwrap_or("".to_owned())
|
serde_json::ser::to_string(&msg_vec).unwrap_or("".to_owned())
|
||||||
|
@ -283,6 +283,8 @@ impl Server {
|
|||||||
s.on_subscribe(conn.clone());
|
s.on_subscribe(conn.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
self.update_enable_retina();
|
||||||
self.connections.insert(conn.id(), conn);
|
self.connections.insert(conn.id(), conn);
|
||||||
*CONN_COUNT.lock().unwrap() = self.connections.len();
|
*CONN_COUNT.lock().unwrap() = self.connections.len();
|
||||||
}
|
}
|
||||||
@ -293,6 +295,8 @@ impl Server {
|
|||||||
}
|
}
|
||||||
self.connections.remove(&conn.id());
|
self.connections.remove(&conn.id());
|
||||||
*CONN_COUNT.lock().unwrap() = self.connections.len();
|
*CONN_COUNT.lock().unwrap() = self.connections.len();
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
self.update_enable_retina();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close_connections(&mut self) {
|
pub fn close_connections(&mut self) {
|
||||||
@ -325,6 +329,8 @@ impl Server {
|
|||||||
} else {
|
} else {
|
||||||
s.on_unsubscribe(conn.id());
|
s.on_unsubscribe(conn.id());
|
||||||
}
|
}
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
self.update_enable_retina();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,6 +380,17 @@ impl Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn update_enable_retina(&self) {
|
||||||
|
let mut video_service_count = 0;
|
||||||
|
for (name, service) in self.services.iter() {
|
||||||
|
if Self::is_video_service_name(&name) && service.ok() {
|
||||||
|
video_service_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*scrap::quartz::ENABLE_RETINA.lock().unwrap() = video_service_count < 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Server {
|
impl Drop for Server {
|
||||||
|
@ -239,6 +239,8 @@ pub struct Connection {
|
|||||||
supported_encoding_flag: (bool, Option<bool>),
|
supported_encoding_flag: (bool, Option<bool>),
|
||||||
services_subed: bool,
|
services_subed: bool,
|
||||||
delayed_read_dir: Option<(String, bool)>,
|
delayed_read_dir: Option<(String, bool)>,
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
retina: Retina,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConnInner {
|
impl ConnInner {
|
||||||
@ -388,6 +390,8 @@ impl Connection {
|
|||||||
supported_encoding_flag: (false, None),
|
supported_encoding_flag: (false, None),
|
||||||
services_subed: false,
|
services_subed: false,
|
||||||
delayed_read_dir: None,
|
delayed_read_dir: None,
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
retina: Retina::default(),
|
||||||
};
|
};
|
||||||
let addr = hbb_common::try_into_v4(addr);
|
let addr = hbb_common::try_into_v4(addr);
|
||||||
if !conn.on_open(addr).await {
|
if !conn.on_open(addr).await {
|
||||||
@ -629,7 +633,8 @@ impl Connection {
|
|||||||
},
|
},
|
||||||
Some((instant, value)) = rx.recv() => {
|
Some((instant, value)) = rx.recv() => {
|
||||||
let latency = instant.elapsed().as_millis() as i64;
|
let latency = instant.elapsed().as_millis() as i64;
|
||||||
let msg: &Message = &value;
|
#[allow(unused_mut)]
|
||||||
|
let mut msg = value;
|
||||||
|
|
||||||
if latency > 1000 {
|
if latency > 1000 {
|
||||||
match &msg.union {
|
match &msg.union {
|
||||||
@ -651,11 +656,20 @@ impl Connection {
|
|||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(message::Union::PeerInfo(..)) => {
|
Some(message::Union::PeerInfo(_pi)) => {
|
||||||
conn.refresh_video_display(None);
|
conn.refresh_video_display(None);
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
conn.retina.set_displays(&_pi.displays);
|
||||||
|
}
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
Some(message::Union::CursorPosition(pos)) => {
|
||||||
|
if let Some(new_msg) = conn.retina.on_cursor_pos(&pos, conn.display_idx) {
|
||||||
|
msg = Arc::new(new_msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
let msg: &Message = &msg;
|
||||||
if let Err(err) = conn.stream.send(msg).await {
|
if let Err(err) = conn.stream.send(msg).await {
|
||||||
conn.on_close(&err.to_string(), false).await;
|
conn.on_close(&err.to_string(), false).await;
|
||||||
break;
|
break;
|
||||||
@ -1229,6 +1243,10 @@ impl Connection {
|
|||||||
Ok(displays) => {
|
Ok(displays) => {
|
||||||
// For compatibility with old versions, we need to send the displays to the peer.
|
// For compatibility with old versions, we need to send the displays to the peer.
|
||||||
// But the displays may be updated later, before creating the video capturer.
|
// But the displays may be updated later, before creating the video capturer.
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
{
|
||||||
|
self.retina.set_displays(&displays);
|
||||||
|
}
|
||||||
pi.displays = displays;
|
pi.displays = displays;
|
||||||
pi.current_display = self.display_idx as _;
|
pi.current_display = self.display_idx as _;
|
||||||
res.set_peer_info(pi);
|
res.set_peer_info(pi);
|
||||||
@ -1811,7 +1829,8 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
} else if self.authorized {
|
} else if self.authorized {
|
||||||
match msg.union {
|
match msg.union {
|
||||||
Some(message::Union::MouseEvent(me)) => {
|
#[allow(unused_mut)]
|
||||||
|
Some(message::Union::MouseEvent(mut me)) => {
|
||||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||||
if let Err(e) = call_main_service_pointer_input("mouse", me.mask, me.x, me.y) {
|
if let Err(e) = call_main_service_pointer_input("mouse", me.mask, me.x, me.y) {
|
||||||
log::debug!("call_main_service_pointer_input fail:{}", e);
|
log::debug!("call_main_service_pointer_input fail:{}", e);
|
||||||
@ -1823,6 +1842,8 @@ impl Connection {
|
|||||||
} else {
|
} else {
|
||||||
MOUSE_MOVE_TIME.store(get_time(), Ordering::SeqCst);
|
MOUSE_MOVE_TIME.store(get_time(), Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
self.retina.on_mouse_event(&mut me, self.display_idx);
|
||||||
self.input_mouse(me, self.inner.id());
|
self.input_mouse(me, self.inner.id());
|
||||||
}
|
}
|
||||||
self.update_auto_disconnect_timer();
|
self.update_auto_disconnect_timer();
|
||||||
@ -3488,6 +3509,54 @@ extern "C" fn connection_shutdown_hook() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct Retina {
|
||||||
|
displays: Vec<DisplayInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
impl Retina {
|
||||||
|
#[inline]
|
||||||
|
fn set_displays(&mut self, displays: &Vec<DisplayInfo>) {
|
||||||
|
self.displays = displays.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn on_mouse_event(&mut self, e: &mut MouseEvent, current: usize) {
|
||||||
|
let Some(d) = self.displays.get(current) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let s = d.scale;
|
||||||
|
if s > 1.0 && e.x >= d.x && e.y >= d.y && e.x < d.x + d.width && e.y < d.y + d.height {
|
||||||
|
e.x = d.x + ((e.x - d.x) as f64 / s) as i32;
|
||||||
|
e.y = d.y + ((e.y - d.y) as f64 / s) as i32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn on_cursor_pos(&mut self, pos: &CursorPosition, current: usize) -> Option<Message> {
|
||||||
|
let Some(d) = self.displays.get(current) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let s = d.scale;
|
||||||
|
if s > 1.0
|
||||||
|
&& pos.x >= d.x
|
||||||
|
&& pos.y >= d.y
|
||||||
|
&& (pos.x - d.x) as f64 * s < d.width as f64
|
||||||
|
&& (pos.y - d.y) as f64 * s < d.height as f64
|
||||||
|
{
|
||||||
|
let mut pos = pos.clone();
|
||||||
|
pos.x = d.x + ((pos.x - d.x) as f64 * s) as i32;
|
||||||
|
pos.y = d.y + ((pos.y - d.y) as f64 * s) as i32;
|
||||||
|
let mut msg = Message::new();
|
||||||
|
msg.set_cursor_position(pos);
|
||||||
|
return Some(msg);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mod raii {
|
mod raii {
|
||||||
// CONN_COUNT: remote connection count in fact
|
// CONN_COUNT: remote connection count in fact
|
||||||
// ALIVE_CONNS: all connections, including unauthorized connections
|
// ALIVE_CONNS: all connections, including unauthorized connections
|
||||||
@ -3578,3 +3647,40 @@ mod raii {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod test {
|
||||||
|
#[allow(unused)]
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
#[test]
|
||||||
|
fn retina() {
|
||||||
|
let mut retina = Retina {
|
||||||
|
displays: vec![DisplayInfo {
|
||||||
|
x: 10,
|
||||||
|
y: 10,
|
||||||
|
width: 1000,
|
||||||
|
height: 1000,
|
||||||
|
scale: 2.0,
|
||||||
|
..Default::default()
|
||||||
|
}],
|
||||||
|
};
|
||||||
|
let mut mouse: MouseEvent = MouseEvent {
|
||||||
|
x: 510,
|
||||||
|
y: 510,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
retina.on_mouse_event(&mut mouse, 0);
|
||||||
|
assert_eq!(mouse.x, 260);
|
||||||
|
assert_eq!(mouse.y, 260);
|
||||||
|
let pos = CursorPosition {
|
||||||
|
x: 260,
|
||||||
|
y: 260,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let msg = retina.on_cursor_pos(&pos, 0).unwrap();
|
||||||
|
let pos = msg.cursor_position();
|
||||||
|
assert_eq!(pos.x, 510);
|
||||||
|
assert_eq!(pos.y, 510);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -273,7 +273,18 @@ pub(super) fn check_update_displays(all: &Vec<Display>) {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|d| {
|
.map(|d| {
|
||||||
let display_name = d.name();
|
let display_name = d.name();
|
||||||
let original_resolution = get_original_resolution(&display_name, d.width(), d.height());
|
#[allow(unused_assignments)]
|
||||||
|
#[allow(unused_mut)]
|
||||||
|
let mut scale = 1.0;
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
{
|
||||||
|
scale = d.scale();
|
||||||
|
}
|
||||||
|
let original_resolution = get_original_resolution(
|
||||||
|
&display_name,
|
||||||
|
((d.width() as f64) / scale).round() as usize,
|
||||||
|
(d.height() as f64 / scale).round() as usize,
|
||||||
|
);
|
||||||
DisplayInfo {
|
DisplayInfo {
|
||||||
x: d.origin().0 as _,
|
x: d.origin().0 as _,
|
||||||
y: d.origin().1 as _,
|
y: d.origin().1 as _,
|
||||||
@ -283,6 +294,7 @@ pub(super) fn check_update_displays(all: &Vec<Display>) {
|
|||||||
online: d.is_online(),
|
online: d.is_online(),
|
||||||
cursor_embedded: false,
|
cursor_embedded: false,
|
||||||
original_resolution,
|
original_resolution,
|
||||||
|
scale,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -14,6 +14,7 @@ pub trait Service: Send + Sync {
|
|||||||
fn join(&self);
|
fn join(&self);
|
||||||
fn get_option(&self, opt: &str) -> Option<String>;
|
fn get_option(&self, opt: &str) -> Option<String>;
|
||||||
fn set_option(&self, opt: &str, val: &str) -> Option<String>;
|
fn set_option(&self, opt: &str, val: &str) -> Option<String>;
|
||||||
|
fn ok(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Subscriber: Default + Send + Sync + 'static {
|
pub trait Subscriber: Default + Send + Sync + 'static {
|
||||||
@ -142,6 +143,12 @@ impl<T: Subscriber + From<ConnInner>> Service for ServiceTmpl<T> {
|
|||||||
.options
|
.options
|
||||||
.insert(opt.to_string(), val.to_string())
|
.insert(opt.to_string(), val.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn ok(&self) -> bool {
|
||||||
|
let lock = self.0.read().unwrap();
|
||||||
|
lock.active && lock.has_subscribes()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Subscriber + From<ConnInner>> Clone for ServiceTmpl<T> {
|
impl<T: Subscriber + From<ConnInner>> Clone for ServiceTmpl<T> {
|
||||||
@ -180,12 +187,6 @@ impl<T: Subscriber + From<ConnInner>> ServiceTmpl<T> {
|
|||||||
self.0.read().unwrap().has_subscribes()
|
self.0.read().unwrap().has_subscribes()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn ok(&self) -> bool {
|
|
||||||
let lock = self.0.read().unwrap();
|
|
||||||
lock.active && lock.has_subscribes()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn snapshot<F>(&self, callback: F) -> ResultType<()>
|
pub fn snapshot<F>(&self, callback: F) -> ResultType<()>
|
||||||
where
|
where
|
||||||
F: FnMut(ServiceSwap<T>) -> ResultType<()>,
|
F: FnMut(ServiceSwap<T>) -> ResultType<()>,
|
||||||
|
Loading…
Reference in New Issue
Block a user