octotablet meldet das Aufsetzen des Stifts vor der Position desselben Frames. Bis dahin galt die alte Position – nähert man den Stift und tippt sofort, lag sie bei der vorherigen Stelle: Der Druck ging an den alten Ort, beim Loslassen hatte sich der Zeiger „bewegt“, egui wertete das nicht als Klick und zeigte nur den Tooltip. Erst das zweite Tippen traf. Auf dem Blatt konnte ein Strich so mit einer Linie von der alten Stelle beginnen. Jetzt wird das Aufsetzen erst nach der Position seines Frames verarbeitet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
149 lines
4.9 KiB
Rust
149 lines
4.9 KiB
Rust
//! Erkennung der Laufzeitumgebung und Wahl des Anzeigesystems (X11 oder Wayland).
|
||
//!
|
||
//! Unter WSL (WSLg) trennt der Wayland-Compositor die Verbindung, sobald die App ein Bild
|
||
//! über Vulkan übergibt ("Connection reset by peer"). Über X11 (Xwayland) läuft sie stabil,
|
||
//! daher wird unter WSL standardmäßig X11 verwendet. `INK_NOTES_DISPLAY=x11|wayland`
|
||
//! übersteuert die Wahl.
|
||
|
||
/// Anzeigesystem, mit dem die Ereignisschleife erzeugt wird.
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||
pub enum DisplayBackend {
|
||
/// Automatische Wahl von winit (Wayland, falls verfügbar, sonst X11)
|
||
Automatic,
|
||
X11,
|
||
Wayland,
|
||
}
|
||
|
||
/// Wählt das Anzeigesystem.
|
||
///
|
||
/// - `override_value`: Inhalt von `INK_NOTES_DISPLAY` (`x11` oder `wayland`, sonst ignoriert)
|
||
/// - `is_wsl`: läuft unter WSL
|
||
/// - `has_x11_display`: `DISPLAY` ist gesetzt (X11/Xwayland erreichbar)
|
||
pub fn choose_display_backend(
|
||
override_value: Option<&str>,
|
||
is_wsl: bool,
|
||
has_x11_display: bool,
|
||
) -> DisplayBackend {
|
||
match override_value
|
||
.map(|v| v.trim().to_ascii_lowercase())
|
||
.as_deref()
|
||
{
|
||
Some("x11") => return DisplayBackend::X11,
|
||
Some("wayland") => return DisplayBackend::Wayland,
|
||
_ => {}
|
||
}
|
||
if is_wsl && has_x11_display {
|
||
DisplayBackend::X11
|
||
} else {
|
||
DisplayBackend::Automatic
|
||
}
|
||
}
|
||
|
||
/// Läuft das Programm unter WSL (Windows-Subsystem für Linux)?
|
||
pub fn is_wsl() -> bool {
|
||
if std::env::var_os("WSL_DISTRO_NAME").is_some() || std::env::var_os("WSL_INTEROP").is_some() {
|
||
return true;
|
||
}
|
||
std::fs::read_to_string("/proc/sys/kernel/osrelease")
|
||
.map(|release| release.to_ascii_lowercase().contains("microsoft"))
|
||
.unwrap_or(false)
|
||
}
|
||
|
||
/// Wahl anhand der aktuellen Umgebung.
|
||
pub fn display_backend_from_env() -> DisplayBackend {
|
||
choose_display_backend(
|
||
std::env::var("INK_NOTES_DISPLAY").ok().as_deref(),
|
||
is_wsl(),
|
||
std::env::var_os("DISPLAY").is_some_and(|d| !d.is_empty()),
|
||
)
|
||
}
|
||
|
||
/// Bringt die Ereignisse eines Tablet-Frames in eine brauchbare Reihenfolge: octotablet meldet
|
||
/// das Aufsetzen des Stifts (`Down`) vor der Position desselben Frames (`Pose`). Bis dahin
|
||
/// gälte noch die alte Position – kam der Stift schnell heran (Annähern und Aufsetzen im selben
|
||
/// Frame), läge sie ganz woanders: Ein Tippen auf einen Knopf ginge daneben, ein Strich begänne
|
||
/// mit einer Linie von der alten Stelle. Hier folgt jedes `Down` auf die nächste `Pose`, spätestens
|
||
/// vor dem nächsten anderen Ereignis.
|
||
pub fn down_after_pose<T>(
|
||
events: impl IntoIterator<Item = T>,
|
||
is_down: impl Fn(&T) -> bool,
|
||
is_pose: impl Fn(&T) -> bool,
|
||
) -> Vec<T> {
|
||
let mut ordered = Vec::new();
|
||
let mut deferred = None;
|
||
for event in events {
|
||
if is_down(&event) {
|
||
if let Some(down) = deferred.replace(event) {
|
||
ordered.push(down);
|
||
}
|
||
continue;
|
||
}
|
||
let pose = is_pose(&event);
|
||
if !pose {
|
||
ordered.extend(deferred.take());
|
||
}
|
||
ordered.push(event);
|
||
if pose {
|
||
ordered.extend(deferred.take());
|
||
}
|
||
}
|
||
ordered.extend(deferred);
|
||
ordered
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_down_follows_pose_of_its_frame() {
|
||
let order = |events: &str| {
|
||
down_after_pose(events.chars(), |c| *c == 'D', |c| *c == 'P')
|
||
.into_iter()
|
||
.collect::<String>()
|
||
};
|
||
// In, Down, Pose, Button, Frame -> Down erst mit der neuen Position
|
||
assert_eq!(order("IDPBF"), "IPDBF");
|
||
// Down ohne Pose im Frame: vor dem Frame-Ende
|
||
assert_eq!(order("DF"), "DF");
|
||
assert_eq!(order("DBF"), "DBF");
|
||
// Am Ende ohne weiteres Ereignis
|
||
assert_eq!(order("PD"), "PD");
|
||
// Andere Ereignisse bleiben unverändert
|
||
assert_eq!(order("PFPFUF"), "PFPFUF");
|
||
assert_eq!(order("IDPFPFUF"), "IPDFPFUF");
|
||
}
|
||
|
||
#[test]
|
||
fn test_choose_display_backend() {
|
||
// WSL mit X11-Display: X11 (Wayland unter WSLg bricht ab)
|
||
assert_eq!(
|
||
choose_display_backend(None, true, true),
|
||
DisplayBackend::X11
|
||
);
|
||
// WSL ohne X11-Display: winit entscheiden lassen
|
||
assert_eq!(
|
||
choose_display_backend(None, true, false),
|
||
DisplayBackend::Automatic
|
||
);
|
||
// Natives Linux: winit entscheiden lassen
|
||
assert_eq!(
|
||
choose_display_backend(None, false, true),
|
||
DisplayBackend::Automatic
|
||
);
|
||
// Übersteuerung
|
||
assert_eq!(
|
||
choose_display_backend(Some("wayland"), true, true),
|
||
DisplayBackend::Wayland
|
||
);
|
||
assert_eq!(
|
||
choose_display_backend(Some(" X11 "), false, true),
|
||
DisplayBackend::X11
|
||
);
|
||
assert_eq!(
|
||
choose_display_backend(Some("quatsch"), true, true),
|
||
DisplayBackend::X11
|
||
);
|
||
}
|
||
}
|