Commit 96942b9aee39
tarball1 file changed+23-53
@@ -16,7 +16,7 @@ use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
1616
use smithay::utils::user_data::UserDataMap;1717
use smithay::utils::{Buffer, Logical, Physical, Point, Rectangle, Scale, Transform};1818
use smithay::wayland::compositor::with_states;19
-use std::collections::HashMap;19
+use std::collections::{HashMap, HashSet};2020
use std::sync::Mutex;2121
2222
/// A theme shape sized for one output scale.@@ -30,10 +30,10 @@ struct Prepared {
3030
pub struct Cursor {3131
theme: xcursor::CursorTheme,3232
size: u32,33
- /// Every image of the shapes read so far, including ones the theme lacks.34
- files: HashMap<CursorIcon, Option<Vec<xcursor::parser::Image>>>,3533
/// Shapes sized for an output scale, in steps of 1/120.36
- sized: HashMap<(CursorIcon, u32), Option<Prepared>>,34
+ sized: HashMap<(CursorIcon, u32), Prepared>,35
+ /// Shapes the theme has no file for, which a retry would not change.36
+ absent: HashSet<CursorIcon>,3737
}3838
3939
impl Cursor {@@ -43,55 +43,29 @@ impl Cursor {
4343
.ok()4444
.and_then(|s| s.parse().ok())4545
.unwrap_or(24u32);46
- let mut cursor = Self {46
+ let cursor = Self {4747
theme: xcursor::CursorTheme::load(&theme),4848
size,49
- files: HashMap::new(),5049
sized: HashMap::new(),50
+ absent: HashSet::new(),5151
};52
- if cursor.file(CursorIcon::Default).is_none() {52
+ if cursor.read(CursorIcon::Default).is_none() {5353
tracing::warn!(theme, "no xcursor theme found, drawing a plain cursor");5454
}55
- // Reading a shape from the theme takes milliseconds, which in a frame56
- // makes it miss, so the ones clients ask for most load up front.57
- for icon in [58
- CursorIcon::Text,59
- CursorIcon::Pointer,60
- CursorIcon::Grab,61
- CursorIcon::Grabbing,62
- CursorIcon::NotAllowed,63
- CursorIcon::Wait,64
- CursorIcon::Progress,65
- CursorIcon::EwResize,66
- CursorIcon::NsResize,67
- CursorIcon::NResize,68
- CursorIcon::SResize,69
- CursorIcon::EResize,70
- CursorIcon::WResize,71
- CursorIcon::NwResize,72
- CursorIcon::NeResize,73
- CursorIcon::SwResize,74
- CursorIcon::SeResize,75
- ] {76
- cursor.file(icon);77
- }7855
cursor7956
}8057
8158
/// The theme's images for `icon`, falling back to the default arrow.82
- fn file(&mut self, icon: CursorIcon) -> Option<&[xcursor::parser::Image]> {83
- if !self.files.contains_key(&icon) {84
- let names = std::iter::once(icon.name()).chain(icon.alt_names().iter().copied());85
- let images = names86
- .chain(["default", "left_ptr"])87
- .find_map(|n| load_file(&self.theme, n));88
- self.files.insert(icon, images);89
- }90
- self.files.get(&icon)?.as_deref()59
+ fn read(&self, icon: CursorIcon) -> Option<Vec<xcursor::parser::Image>> {60
+ let names = std::iter::once(icon.name()).chain(icon.alt_names().iter().copied());61
+ names62
+ .chain(["default", "left_ptr"])63
+ .find_map(|n| load_file(&self.theme, n))9164
}9265
9366
/// The theme's image nearest the cursor size times `scale`, stretched to94
- /// exactly that size so it covers whole pixels.67
+ /// exactly that size so it covers whole pixels. Only that image is kept,68
+ /// and an upload that fails is retried on the next call.9569
fn sized(9670
&mut self,9771
renderer: &mut VulkanRenderer,@@ -99,21 +73,17 @@ impl Cursor {
9973
scale: f64,10074
) -> Option<&Prepared> {10175
let key = (icon, (scale * 120.0).round() as u32);102
- if !self.sized.contains_key(&key) {76
+ if !self.sized.contains_key(&key) && !self.absent.contains(&icon) {77
+ let Some(images) = self.read(icon) else {78
+ self.absent.insert(icon);79
+ return None;80
+ };10381
let wanted = ((f64::from(self.size) * scale).round() as u32).max(1);104
- let prepared = self105
- .file(icon)106
- .and_then(|images| images.iter().min_by_key(|i| i.size.abs_diff(wanted)))107
- .and_then(|image| {108
- prepare(109
- renderer,110
- image,111
- f64::from(wanted) / f64::from(image.size.max(1)),112
- )113
- });114
- self.sized.insert(key, prepared);82
+ let image = images.iter().min_by_key(|i| i.size.abs_diff(wanted))?;83
+ let ratio = f64::from(wanted) / f64::from(image.size.max(1));84
+ self.sized.insert(key, prepare(renderer, image, ratio)?);11585
}116
- self.sized.get(&key)?.as_ref()86
+ self.sized.get(&key)11787
}11888
11989
/// Elements for the pointer at `pos`, in output-local coordinates.