mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-14 19:26:56 -04:00
Cursors: paint the tool cursors on Wayland, where the compositor showed the bitmap twice too big (fixes #1645)
This commit is contained in:
1 parent
3412d3a073
commit
e50bd58146
4 files changed
+37
-1
No files matched your search
@@ -489,6 +489,8 @@ fn start_pick(request: PickRequest, parent: &Parent, ui: &egui::Context) -> Opti
|
||||
|
||||
/// The host's services; `ui` is woken when a file dialog answers.
|
||||
fn services(parent: Parent, ui: egui::Context) -> Services {
|
||||
use winit::raw_window_handle::{HasWindowHandle as _, RawWindowHandle};
|
||||
let wayland = parent.as_ref().and_then(|w| w.window_handle().ok()).is_some_and(|h| matches!(h.as_raw(), RawWindowHandle::Wayland(_)));
|
||||
let (p1, p2, p3, p4, p5) = (parent.clone(), parent.clone(), parent.clone(), parent.clone(), parent);
|
||||
Services {
|
||||
pick_open: Some(Box::new(move |pick: &FilePick| pick_now(PickRequest::Open(pick.clone()), &p1).into_iter().next())),
|
||||
@@ -498,6 +500,7 @@ fn services(parent: Parent, ui: egui::Context) -> Services {
|
||||
// dialogs run the window's events while they are open.
|
||||
start_pick: cfg!(unix).then(|| Box::new(move |request: PickRequest| start_pick(request, &p5, &ui)) as vectorcraft_ui_egui::picks::StartPick),
|
||||
dialogs_are_sheets: cfg!(target_os = "macos"),
|
||||
wayland,
|
||||
read: Some(Box::new(|p: &str| std::fs::read(p).map_err(|e| e.to_string()))),
|
||||
write: Some(Box::new(write_file)),
|
||||
// Background Save and Export write from a worker thread.
|
||||
|
||||
@@ -492,7 +492,7 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
match ui.input(|i| i.pointer.hover_pos()) {
|
||||
// An OS cursor: the system moves it at once, where a painted one trails the pointer
|
||||
// (#444). The system cursor stands in for cursors without a glyph.
|
||||
Some(_) if custom && crate::cursors::OS_CURSORS => {
|
||||
Some(_) if custom && crate::cursors::os_cursors(crate::cursors::OS_CURSORS, app.services.wayland) => {
|
||||
let ppp = ui.ctx().pixels_per_point() / ui_scale;
|
||||
ui.ctx().set_cursor_image(app.canvas.cursors.get(c, ppp));
|
||||
cursor_icon(c)
|
||||
|
||||
@@ -386,6 +386,14 @@ pub fn paint(painter: &Painter, c: Cursor, p: Pos2, scale: f32) -> bool {
|
||||
/// bitmap cursors there): those paint them into the window ([`paint`]).
|
||||
pub const OS_CURSORS: bool = !cfg!(any(target_os = "macos", target_arch = "wasm32"));
|
||||
|
||||
/// Does this window show the glyphs as OS cursors, on a build that can ([`OS_CURSORS`])? Not on
|
||||
/// Wayland, where the compositor decides how big a cursor bitmap shows: Hyprland shows each pixel
|
||||
/// as a point, twice too big on a 2× display (#1645). The window paints them there, as PhotoCraft
|
||||
/// and PdfCraft do.
|
||||
pub fn os_cursors(build: bool, wayland: bool) -> bool {
|
||||
build && !wayland
|
||||
}
|
||||
|
||||
/// The cursor bitmaps handed to the OS, by (cursor, pixels per point): each glyph is rasterized
|
||||
/// once, and handing the same `Arc` every frame keeps the window's OS cursor instead of making a
|
||||
/// new one.
|
||||
@@ -655,6 +663,21 @@ mod tests {
|
||||
assert!(off.platform_output.cursor_image.is_none());
|
||||
}
|
||||
|
||||
/// On Wayland the glyph is painted and the pointer hidden over the canvas, on every build (#1645).
|
||||
#[test]
|
||||
fn a_wayland_window_paints_the_tool_cursor() {
|
||||
let mut app = VectorcraftApp::new(Session::new(), crate::Services { wayland: true, ..Default::default() });
|
||||
app.run("file.new", json!({"width": 400, "height": 300})).unwrap();
|
||||
let ctx = egui::Context::default();
|
||||
for _ in 0..3 {
|
||||
frame(&mut app, &ctx, vec![]);
|
||||
}
|
||||
let over = app.canvas_rect.unwrap().center();
|
||||
let out = frame(&mut app, &ctx, vec![egui::Event::PointerMoved(over)]);
|
||||
assert!(out.platform_output.cursor_image.is_none());
|
||||
assert_eq!(out.platform_output.cursor_icon, egui::CursorIcon::None);
|
||||
}
|
||||
|
||||
/// User Interface › Scale Cursor Proportional to UI (#394): off, the tool cursors keep their
|
||||
/// size whatever the UI Scaling; on, they grow with it.
|
||||
#[test]
|
||||
@@ -692,6 +715,13 @@ mod tests {
|
||||
assert!(full.contains(pos2(100.0, 100.0)) && half.contains(pos2(100.0, 100.0)), "{full:?} {half:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wayland_windows_paint_the_glyphs() {
|
||||
assert!(os_cursors(true, false), "Windows, X11");
|
||||
assert!(!os_cursors(true, true), "Wayland: the compositor would size the bitmap (#1645)");
|
||||
assert!(!os_cursors(false, false) && !os_cursors(false, true), "macOS, the web");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn arrow_hotspot_is_tip() {
|
||||
let pts = arrow_points(pos2(10.0, 20.0));
|
||||
|
||||
@@ -261,6 +261,9 @@ pub struct Services {
|
||||
/// [`Self::start_pick`]'s dialogs are sheets on the window (macOS): while one is open the app
|
||||
/// neither quits nor closes documents, as under the modal dialog before.
|
||||
pub dialogs_are_sheets: bool,
|
||||
/// The window is on Wayland: the tool cursors are painted into it instead of handed to the
|
||||
/// compositor as bitmaps ([`cursors::os_cursors`]).
|
||||
pub wayland: bool,
|
||||
}
|
||||
|
||||
/// Cached canvas raster.
|
||||
|
||||
Reference in new issue
Block a user