Skip to content

Commit 39bc493

Browse files
desktop support ui scaling
1 parent 03ffc80 commit 39bc493

File tree

17 files changed

+176
-114
lines changed

17 files changed

+176
-114
lines changed

desktop/src/app.rs

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::thread;
88
use std::time::Duration;
99
use std::time::Instant;
1010
use winit::application::ApplicationHandler;
11+
use winit::dpi::PhysicalSize;
1112
use winit::event::WindowEvent;
1213
use winit::event_loop::ActiveEventLoop;
1314
use winit::event_loop::ControlFlow;
@@ -25,8 +26,9 @@ use crate::wrapper::{DesktopWrapper, NodeGraphExecutionResult, WgpuContext, seri
2526
pub(crate) struct App {
2627
cef_context: Box<dyn cef::CefContext>,
2728
window: Option<Window>,
29+
window_scale: f64,
2830
cef_schedule: Option<Instant>,
29-
cef_window_size_sender: Sender<cef::WindowSize>,
31+
cef_view_info_sender: Sender<cef::ViewInfoUpdate>,
3032
graphics_state: Option<GraphicsState>,
3133
wgpu_context: WgpuContext,
3234
app_event_receiver: Receiver<AppEvent>,
@@ -44,7 +46,7 @@ pub(crate) struct App {
4446
impl App {
4547
pub(crate) fn new(
4648
cef_context: Box<dyn cef::CefContext>,
47-
window_size_sender: Sender<cef::WindowSize>,
49+
cef_view_info_sender: Sender<cef::ViewInfoUpdate>,
4850
wgpu_context: WgpuContext,
4951
app_event_receiver: Receiver<AppEvent>,
5052
app_event_scheduler: AppEventScheduler,
@@ -66,9 +68,10 @@ impl App {
6668
Self {
6769
cef_context,
6870
window: None,
71+
window_scale: 1.0,
6972
cef_schedule: Some(Instant::now()),
7073
graphics_state: None,
71-
cef_window_size_sender: window_size_sender,
74+
cef_view_info_sender,
7275
wgpu_context,
7376
app_event_receiver,
7477
app_event_scheduler,
@@ -147,19 +150,19 @@ impl App {
147150
}
148151
});
149152
}
150-
DesktopFrontendMessage::UpdateViewportBounds { x, y, width, height } => {
153+
DesktopFrontendMessage::UpdateViewportPhysicalBounds { x, y, width, height } => {
151154
if let Some(graphics_state) = &mut self.graphics_state
152155
&& let Some(window) = &self.window
153156
{
154157
let window_size = window.surface_size();
155158

156-
let viewport_offset_x = x / window_size.width as f32;
157-
let viewport_offset_y = y / window_size.height as f32;
158-
graphics_state.set_viewport_offset([viewport_offset_x, viewport_offset_y]);
159+
let viewport_offset_x = x / window_size.width as f64;
160+
let viewport_offset_y = y / window_size.height as f64;
161+
graphics_state.set_viewport_offset([viewport_offset_x as f32, viewport_offset_y as f32]);
159162

160-
let viewport_scale_x = if width != 0.0 { window_size.width as f32 / width } else { 1.0 };
161-
let viewport_scale_y = if height != 0.0 { window_size.height as f32 / height } else { 1.0 };
162-
graphics_state.set_viewport_scale([viewport_scale_x, viewport_scale_y]);
163+
let viewport_scale_x = if width != 0.0 { window_size.width as f64 / width } else { 1.0 };
164+
let viewport_scale_y = if height != 0.0 { window_size.height as f64 / height } else { 1.0 };
165+
graphics_state.set_viewport_scale([viewport_scale_x as f32, viewport_scale_y as f32]);
163166
}
164167
}
165168
DesktopFrontendMessage::UpdateOverlays(scene) => {
@@ -352,14 +355,17 @@ impl App {
352355
impl ApplicationHandler for App {
353356
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
354357
let window = Window::new(event_loop, self.app_event_scheduler.clone());
358+
359+
self.window_scale = window.scale_factor();
360+
let _ = self.cef_view_info_sender.send(cef::ViewInfoUpdate::Scale(self.window_scale));
361+
self.cef_context.notify_view_info_changed();
362+
355363
self.window = Some(window);
356364

357365
let graphics_state = GraphicsState::new(self.window.as_ref().unwrap(), self.wgpu_context.clone());
358366

359367
self.graphics_state = Some(graphics_state);
360368

361-
tracing::info!("Winit window created and ready");
362-
363369
self.desktop_wrapper.init(self.wgpu_context.clone());
364370

365371
#[cfg(target_os = "windows")]
@@ -378,20 +384,28 @@ impl ApplicationHandler for App {
378384
}
379385

380386
fn window_event(&mut self, event_loop: &dyn ActiveEventLoop, _window_id: WindowId, event: WindowEvent) {
381-
self.cef_context.handle_window_event(&event);
387+
self.cef_context.handle_window_event(&event, self.window_scale);
382388

383389
match event {
384390
WindowEvent::CloseRequested => {
385391
self.app_event_scheduler.schedule(AppEvent::CloseWindow);
386392
}
387-
WindowEvent::SurfaceResized(size) => {
388-
let _ = self.cef_window_size_sender.send(size.into());
389-
self.cef_context.notify_of_resize();
393+
WindowEvent::SurfaceResized(PhysicalSize { width, height }) => {
394+
let _ = self.cef_view_info_sender.send(cef::ViewInfoUpdate::Size {
395+
width: width as usize,
396+
height: height as usize,
397+
});
398+
self.cef_context.notify_view_info_changed();
390399
if let Some(window) = &self.window {
391400
let maximized = window.is_maximized();
392401
self.app_event_scheduler.schedule(AppEvent::DesktopWrapperMessage(DesktopWrapperMessage::UpdateMaximized { maximized }));
393402
}
394403
}
404+
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
405+
self.window_scale = scale_factor;
406+
let _ = self.cef_view_info_sender.send(cef::ViewInfoUpdate::Scale(self.window_scale));
407+
self.cef_context.notify_view_info_changed();
408+
}
395409
WindowEvent::RedrawRequested => {
396410
let Some(ref mut graphics_state) = self.graphics_state else { return };
397411
// Only rerender once we have a new UI texture to display

desktop/src/cef.rs

Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ use texture_import::SharedTextureHandle;
3939
pub(crate) use context::{CefContext, CefContextBuilder, InitError};
4040

4141
pub(crate) trait CefEventHandler: Clone + Send + Sync + 'static {
42-
fn window_size(&self) -> WindowSize;
42+
fn view_info(&self) -> ViewInfo;
4343
fn draw<'a>(&self, frame_buffer: FrameBufferRef<'a>);
4444
#[cfg(feature = "accelerated_paint")]
4545
fn draw_gpu(&self, shared_texture: SharedTextureHandle);
@@ -53,21 +53,48 @@ pub(crate) trait CefEventHandler: Clone + Send + Sync + 'static {
5353
}
5454

5555
#[derive(Clone, Copy)]
56-
pub(crate) struct WindowSize {
57-
pub(crate) width: usize,
58-
pub(crate) height: usize,
56+
pub(crate) struct ViewInfo {
57+
width: usize,
58+
height: usize,
59+
scale: f64,
5960
}
60-
impl WindowSize {
61-
pub(crate) fn new(width: usize, height: usize) -> Self {
62-
Self { width, height }
61+
impl ViewInfo {
62+
pub(crate) fn new() -> Self {
63+
Self { width: 1, height: 1, scale: 1.0 }
64+
}
65+
pub(crate) fn apply_update(&mut self, update: ViewInfoUpdate) {
66+
match update {
67+
ViewInfoUpdate::Size { width, height } if width > 0 && height > 0 => {
68+
self.width = width;
69+
self.height = height;
70+
}
71+
ViewInfoUpdate::Scale(scale) if scale > 0.0 => {
72+
self.scale = scale;
73+
}
74+
_ => {}
75+
}
76+
}
77+
pub(crate) fn scale(&self) -> f64 {
78+
self.scale
79+
}
80+
pub(crate) fn scaled_width(&self) -> usize {
81+
(self.width as f64 / self.scale).round() as usize
82+
}
83+
pub(crate) fn scaled_height(&self) -> usize {
84+
(self.height as f64 / self.scale).round() as usize
6385
}
6486
}
65-
impl From<winit::dpi::PhysicalSize<u32>> for WindowSize {
66-
fn from(size: winit::dpi::PhysicalSize<u32>) -> Self {
67-
Self::new(size.width as usize, size.height as usize)
87+
impl Default for ViewInfo {
88+
fn default() -> Self {
89+
Self::new()
6890
}
6991
}
7092

93+
pub(crate) enum ViewInfoUpdate {
94+
Size { width: usize, height: usize },
95+
Scale(f64),
96+
}
97+
7198
#[derive(Clone)]
7299
pub(crate) struct Resource {
73100
pub(crate) reader: ResourceReader,
@@ -93,30 +120,30 @@ impl Read for ResourceReader {
93120
pub(crate) struct CefHandler {
94121
wgpu_context: WgpuContext,
95122
app_event_scheduler: AppEventScheduler,
96-
window_size_receiver: Arc<Mutex<WindowSizeReceiver>>,
123+
view_info_receiver: Arc<Mutex<ViewInfoReceiver>>,
97124
}
98125

99126
impl CefHandler {
100-
pub(crate) fn new(wgpu_context: WgpuContext, app_event_scheduler: AppEventScheduler, window_size_receiver: Receiver<WindowSize>) -> Self {
127+
pub(crate) fn new(wgpu_context: WgpuContext, app_event_scheduler: AppEventScheduler, view_info_receiver: Receiver<ViewInfoUpdate>) -> Self {
101128
Self {
102129
wgpu_context,
103130
app_event_scheduler,
104-
window_size_receiver: Arc::new(Mutex::new(WindowSizeReceiver::new(window_size_receiver))),
131+
view_info_receiver: Arc::new(Mutex::new(ViewInfoReceiver::new(view_info_receiver))),
105132
}
106133
}
107134
}
108135

109136
impl CefEventHandler for CefHandler {
110-
fn window_size(&self) -> WindowSize {
111-
let Ok(mut guard) = self.window_size_receiver.lock() else {
112-
tracing::error!("Failed to lock window_size_receiver");
113-
return WindowSize::new(1, 1);
137+
fn view_info(&self) -> ViewInfo {
138+
let Ok(mut guard) = self.view_info_receiver.lock() else {
139+
tracing::error!("Failed to lock view_info_receiver");
140+
return ViewInfo::new();
114141
};
115-
let WindowSizeReceiver { receiver, window_size } = &mut *guard;
116-
for new_window_size in receiver.try_iter() {
117-
*window_size = new_window_size;
142+
let ViewInfoReceiver { receiver, view_info } = &mut *guard;
143+
for update in receiver.try_iter() {
144+
view_info.apply_update(update);
118145
}
119-
*window_size
146+
*view_info
120147
}
121148
fn draw<'a>(&self, frame_buffer: FrameBufferRef<'a>) {
122149
let width = frame_buffer.width() as u32;
@@ -246,15 +273,12 @@ impl CefEventHandler for CefHandler {
246273
}
247274
}
248275

249-
struct WindowSizeReceiver {
250-
window_size: WindowSize,
251-
receiver: Receiver<WindowSize>,
276+
struct ViewInfoReceiver {
277+
view_info: ViewInfo,
278+
receiver: Receiver<ViewInfoUpdate>,
252279
}
253-
impl WindowSizeReceiver {
254-
fn new(window_size_receiver: Receiver<WindowSize>) -> Self {
255-
Self {
256-
window_size: WindowSize { width: 1, height: 1 },
257-
receiver: window_size_receiver,
258-
}
280+
impl ViewInfoReceiver {
281+
fn new(receiver: Receiver<ViewInfoUpdate>) -> Self {
282+
Self { view_info: ViewInfo::new(), receiver }
259283
}
260284
}

desktop/src/cef/context.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ pub(crate) use builder::{CefContextBuilder, InitError};
88
pub(crate) trait CefContext {
99
fn work(&mut self);
1010

11-
fn handle_window_event(&mut self, event: &winit::event::WindowEvent);
11+
fn handle_window_event(&mut self, event: &winit::event::WindowEvent, scale: f64);
1212

13-
fn notify_of_resize(&self);
13+
fn notify_view_info_changed(&self);
1414

1515
fn send_web_message(&self, message: Vec<u8>);
1616
}

desktop/src/cef/context/multithreaded.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,22 @@ impl CefContext for MultiThreadedCefContextProxy {
1919
// CEF handles its own message loop in multi-threaded mode
2020
}
2121

22-
fn handle_window_event(&mut self, event: &WindowEvent) {
22+
fn handle_window_event(&mut self, event: &WindowEvent, scale: f64) {
2323
let event_clone = event.clone();
2424
run_on_ui_thread(move || {
2525
CONTEXT.with(|b| {
2626
if let Some(context) = b.borrow_mut().as_mut() {
27-
context.handle_window_event(&event_clone);
27+
context.handle_window_event(&event_clone, scale);
2828
}
2929
});
3030
});
3131
}
3232

33-
fn notify_of_resize(&self) {
33+
fn notify_view_info_changed(&self) {
3434
run_on_ui_thread(move || {
3535
CONTEXT.with(|b| {
3636
if let Some(context) = b.borrow_mut().as_mut() {
37-
context.notify_of_resize();
37+
context.notify_view_info_changed();
3838
}
3939
});
4040
});

desktop/src/cef/context/singlethreaded.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
use cef::{Browser, ImplBrowser, ImplBrowserHost};
1+
use cef::{Browser, ImplBrowser};
22
use winit::event::WindowEvent;
33

44
use crate::cef::input;
55
use crate::cef::input::InputState;
6+
use crate::cef::internal::NotifyViewInfoChanged;
67
use crate::cef::ipc::{MessageType, SendMessage};
78

89
use super::CefContext;
@@ -18,12 +19,12 @@ impl CefContext for SingleThreadedCefContext {
1819
cef::do_message_loop_work();
1920
}
2021

21-
fn handle_window_event(&mut self, event: &WindowEvent) {
22-
input::handle_window_event(&self.browser, &mut self.input_state, event)
22+
fn handle_window_event(&mut self, event: &WindowEvent, scale: f64) {
23+
input::handle_window_event(&self.browser, &mut self.input_state, event, scale)
2324
}
2425

25-
fn notify_of_resize(&self) {
26-
self.browser.host().unwrap().was_resized();
26+
fn notify_view_info_changed(&self) {
27+
self.browser.host().unwrap().notify_view_info_changed();
2728
}
2829

2930
fn send_web_message(&self, message: Vec<u8>) {

desktop/src/cef/input.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
use cef::sys::{cef_event_flags_t, cef_key_event_type_t, cef_mouse_button_type_t};
22
use cef::{Browser, ImplBrowser, ImplBrowserHost, KeyEvent, KeyEventType, MouseEvent};
33
use std::time::Instant;
4-
use winit::dpi::PhysicalPosition;
4+
use winit::dpi::LogicalPosition;
55
use winit::event::{ButtonSource, ElementState, MouseButton, MouseScrollDelta, WindowEvent};
66

77
mod keymap;
88
use keymap::{ToNativeKeycode, ToVKBits};
99

1010
use super::consts::{MULTICLICK_ALLOWED_TRAVEL, MULTICLICK_TIMEOUT, PINCH_ZOOM_SPEED, SCROLL_LINE_HEIGHT, SCROLL_LINE_WIDTH, SCROLL_SPEED_X, SCROLL_SPEED_Y};
1111

12-
pub(crate) fn handle_window_event(browser: &Browser, input_state: &mut InputState, event: &WindowEvent) {
12+
pub(crate) fn handle_window_event(browser: &Browser, input_state: &mut InputState, event: &WindowEvent, scale: f64) {
1313
match event {
1414
WindowEvent::PointerMoved { position, .. } | WindowEvent::PointerEntered { position, .. } => {
15-
input_state.cursor_move(position);
15+
input_state.cursor_move(&position.to_logical(scale));
1616

1717
let Some(host) = browser.host() else { return };
1818
host.send_mouse_move_event(Some(&input_state.into()), 0);
1919
}
2020
WindowEvent::PointerLeft { position, .. } => {
2121
if let Some(position) = position {
22-
input_state.cursor_move(position);
22+
input_state.cursor_move(&position.to_logical(scale));
2323
}
2424

2525
let Some(host) = browser.host() else { return };
@@ -159,7 +159,7 @@ impl InputState {
159159
self.modifiers = *modifiers;
160160
}
161161

162-
fn cursor_move(&mut self, position: &PhysicalPosition<f64>) {
162+
fn cursor_move(&mut self, position: &LogicalPosition<f64>) {
163163
self.mouse_position = position.into();
164164
}
165165

@@ -206,8 +206,8 @@ pub(crate) struct MousePosition {
206206
x: usize,
207207
y: usize,
208208
}
209-
impl From<&PhysicalPosition<f64>> for MousePosition {
210-
fn from(position: &PhysicalPosition<f64>) -> Self {
209+
impl From<&LogicalPosition<f64>> for MousePosition {
210+
fn from(position: &LogicalPosition<f64>) -> Self {
211211
Self {
212212
x: position.x as usize,
213213
y: position.y as usize,

desktop/src/cef/internal.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,13 @@ pub(super) use browser_process_client::BrowserProcessClientImpl;
2222
pub(super) use render_handler::RenderHandlerImpl;
2323
pub(super) use render_process_app::RenderProcessAppImpl;
2424
pub(super) use scheme_handler_factory::SchemeHandlerFactoryImpl;
25+
26+
pub(super) trait NotifyViewInfoChanged {
27+
fn notify_view_info_changed(&self);
28+
}
29+
impl<T: cef::ImplBrowserHost> NotifyViewInfoChanged for T {
30+
fn notify_view_info_changed(&self) {
31+
self.notify_screen_info_changed();
32+
self.was_resized();
33+
}
34+
}

0 commit comments

Comments
 (0)