fix: cursor, macos, text (#12794)

Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
fufesou
2025-09-01 15:34:48 +08:00
committed by GitHub
parent d499098c4f
commit 7948d3144a
2 changed files with 50 additions and 13 deletions

View File

@@ -3,11 +3,11 @@ use core_graphics::context::CGContextRef;
use foreign_types::ForeignTypeRef; use foreign_types::ForeignTypeRef;
use hbb_common::{bail, log, ResultType}; use hbb_common::{bail, log, ResultType};
use objc::{class, msg_send, runtime::Object, sel, sel_impl}; use objc::{class, msg_send, runtime::Object, sel, sel_impl};
use piet::{kurbo::BezPath, RenderContext}; use piet::{kurbo::BezPath, FontFamily, RenderContext, Text, TextLayoutBuilder};
use piet_coregraphics::CoreGraphicsContext; use piet_coregraphics::{CoreGraphicsContext, CoreGraphicsTextLayout};
use std::{collections::HashMap, sync::Arc, time::Instant}; use std::{collections::HashMap, sync::Arc, time::Instant};
use tao::{ use tao::{
dpi::{LogicalSize, PhysicalPosition, PhysicalSize}, dpi::{LogicalSize, PhysicalPosition},
event::{Event, StartCause, WindowEvent}, event::{Event, StartCause, WindowEvent},
event_loop::{ControlFlow, EventLoop, EventLoopBuilder}, event_loop::{ControlFlow, EventLoop, EventLoopBuilder},
platform::macos::MonitorHandleExtMacOS, platform::macos::MonitorHandleExtMacOS,
@@ -16,6 +16,8 @@ use tao::{
}; };
const MAXIMUM_WINDOW_LEVEL: i64 = 2147483647; const MAXIMUM_WINDOW_LEVEL: i64 = 2147483647;
const CURSOR_TEXT_FONT_SIZE: f64 = 14.0;
const CURSOR_TEXT_OFFSET: f64 = 20.0;
struct WindowState { struct WindowState {
window: Arc<Window>, window: Arc<Window>,
@@ -31,6 +33,12 @@ struct Ripple {
start_time: Instant, start_time: Instant,
} }
struct CursorInfo {
window_id: WindowId,
text_key: (String, u32),
cursor: Cursor,
}
fn set_window_properties(window: &Arc<Window>) -> ResultType<()> { fn set_window_properties(window: &Arc<Window>) -> ResultType<()> {
let handle = window.window_handle()?; let handle = window.window_handle()?;
if let RawWindowHandle::AppKit(appkit_handle) = handle.as_raw() { if let RawWindowHandle::AppKit(appkit_handle) = handle.as_raw() {
@@ -108,7 +116,8 @@ fn draw_cursors(
windows: &Vec<WindowState>, windows: &Vec<WindowState>,
window_id: WindowId, window_id: WindowId,
window_ripples: &mut HashMap<WindowId, Vec<Ripple>>, window_ripples: &mut HashMap<WindowId, Vec<Ripple>>,
last_cursors: &HashMap<String, (WindowId, Cursor)>, last_cursors: &HashMap<String, CursorInfo>,
map_cursor_text: &mut HashMap<(String, u32), CoreGraphicsTextLayout>,
) { ) {
for window in windows.iter() { for window in windows.iter() {
if window.window.id() != window_id { if window.window.id() != window_id {
@@ -154,10 +163,11 @@ fn draw_cursors(
}); });
} }
for (wid, cursor) in last_cursors.values() { for info in last_cursors.values() {
if *wid != window.window.id() { if info.window_id != window.window.id() {
continue; continue;
} }
let cursor = &info.cursor;
let (x, y) = (cursor.x as f64, cursor.y as f64); let (x, y) = (cursor.x as f64, cursor.y as f64);
let size = 1.0; let size = 1.0;
@@ -178,6 +188,23 @@ fn draw_cursors(
(cursor.argb >> 24 & 0xFF) as u8, (cursor.argb >> 24 & 0xFF) as u8,
); );
context.fill(pb, &color); context.fill(pb, &color);
let pos =
(x + CURSOR_TEXT_OFFSET * size, y + CURSOR_TEXT_OFFSET * size);
if let Some(layout) = map_cursor_text.get(&info.text_key) {
context.draw_text(layout, pos);
} else {
let text = context.text();
if let Ok(layout) = text
.new_text_layout(cursor.text.clone())
.font(FontFamily::SYSTEM_UI, CURSOR_TEXT_FONT_SIZE)
.text_color(color)
.build()
{
context.draw_text(&layout, pos);
map_cursor_text.insert(info.text_key.clone(), layout);
}
}
} }
if let Err(e) = context.finish() { if let Err(e) = context.finish() {
log::error!("Failed to draw cursor: {}", e); log::error!("Failed to draw cursor: {}", e);
@@ -209,7 +236,8 @@ pub(super) fn create_event_loop() -> ResultType<()> {
}; };
let mut window_ripples: HashMap<WindowId, Vec<Ripple>> = HashMap::new(); let mut window_ripples: HashMap<WindowId, Vec<Ripple>> = HashMap::new();
let mut last_cursors: HashMap<String, (WindowId, Cursor)> = HashMap::new(); let mut last_cursors: HashMap<String, CursorInfo> = HashMap::new();
let mut map_cursor_text: HashMap<(String, u32), CoreGraphicsTextLayout> = HashMap::new();
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Poll; *control_flow = ControlFlow::Poll;
@@ -229,7 +257,13 @@ pub(super) fn create_event_loop() -> ResultType<()> {
_ => {} _ => {}
}, },
Event::RedrawRequested(window_id) => { Event::RedrawRequested(window_id) => {
draw_cursors(&windows, window_id, &mut window_ripples, &last_cursors); draw_cursors(
&windows,
window_id,
&mut window_ripples,
&last_cursors,
&mut map_cursor_text,
);
} }
Event::MainEventsCleared => { Event::MainEventsCleared => {
for window in windows.iter() { for window in windows.iter() {
@@ -268,14 +302,15 @@ pub(super) fn create_event_loop() -> ResultType<()> {
} }
last_cursors.insert( last_cursors.insert(
k, k,
( CursorInfo {
window.window.id(), window_id: window.window.id(),
Cursor { text_key: (cursor.text.clone(), cursor.argb),
cursor: Cursor {
x: (cursor.x - window.display_origin.0 as f32), x: (cursor.x - window.display_origin.0 as f32),
y: (cursor.y - window.display_origin.1 as f32), y: (cursor.y - window.display_origin.1 as f32),
..cursor ..cursor
}, },
), },
); );
window.window.request_redraw(); window.window.request_redraw();
break; break;

View File

@@ -1,12 +1,13 @@
use super::{create_event_loop, CustomEvent}; use super::{create_event_loop, CustomEvent};
use crate::ipc::{new_listener, Connection, Data}; use crate::ipc::{new_listener, Connection, Data};
#[cfg(any(target_os = "windows", target_os = "linux"))]
use hbb_common::ResultType;
use hbb_common::{ use hbb_common::{
allow_err, log, allow_err, log,
tokio::{ tokio::{
self, self,
sync::mpsc::{unbounded_channel, UnboundedReceiver}, sync::mpsc::{unbounded_channel, UnboundedReceiver},
}, },
ResultType,
}; };
use lazy_static::lazy_static; use lazy_static::lazy_static;
use std::sync::RwLock; use std::sync::RwLock;
@@ -99,6 +100,7 @@ async fn handle_new_stream(mut conn: Connection) {
}); });
} }
#[cfg(any(target_os = "windows", target_os = "linux"))]
pub(super) fn get_displays_rect() -> ResultType<(i32, i32, u32, u32)> { pub(super) fn get_displays_rect() -> ResultType<(i32, i32, u32, u32)> {
let displays = crate::server::display_service::try_get_displays()?; let displays = crate::server::display_service::try_get_displays()?;
let mut min_x = i32::MAX; let mut min_x = i32::MAX;