From 9e96451243e183aa2e4ba70383f40174f7147596 Mon Sep 17 00:00:00 2001 From: Alberto Date: Fri, 19 Jun 2026 08:14:59 +0200 Subject: [PATCH 1/2] Fall back to GetCanvas() when the task framebuffer is unavailable GetCurrentTask()/GetTaskFramebuffer() are only wired up on-device. In the desktop SDK emulator GetCurrentTask() returns -1 and the task framebuffer is null, so Screen::new() panics before anything is drawn. Fall back to the global canvas (GetCanvas) -- the same icanvas_s, populated in both environments. GetTaskFramebufferInfo is likewise task-only, so skip it on the emulator instead of unwrapping a null pointer. Co-Authored-By: Claude Opus 4.8 (1M context) --- inkview/src/screen.rs | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/inkview/src/screen.rs b/inkview/src/screen.rs index e79b836..3e7f290 100644 --- a/inkview/src/screen.rs +++ b/inkview/src/screen.rs @@ -53,17 +53,39 @@ pub struct Screen<'a> { } impl<'a> Screen<'a> { + /// Whether we're running under the desktop SDK emulator rather than on-device. + /// + /// The task-framebuffer API (`GetCurrentTask`/`GetTaskFramebuffer`) is only + /// wired up on-device: the emulator's `GetCurrentTask()` returns -1 (on both + /// the main and worker threads), while the device returns a real task id. + fn is_emulator(iv: &Inkview) -> bool { + unsafe { iv.GetCurrentTask() < 0 } + } + pub fn new(iv: &'a Inkview) -> Self { unsafe { iv.SetCurrentApplicationAttribute(APPLICATION_ATTRIBUTE_APPLICATION_READER, 1); } - let fb = unsafe { iv.GetTaskFramebuffer(iv.GetCurrentTask()).as_mut() } - .expect("Failed to get current task framebuffer while creating new screen."); + // On the emulator the task framebuffer is null, so fall back to the global + // canvas (GetCanvas) — the same `icanvas_s`, populated in both environments. + // We keep this as a null-check (not gated on `is_emulator`) so it still + // recovers if a real task ever hands back a null framebuffer. + let fb = unsafe { + let task_fb = iv.GetTaskFramebuffer(iv.GetCurrentTask()); + if task_fb.is_null() { + iv.GetCanvas().as_mut() + } else { + task_fb.as_mut() + } + } + .expect("Failed to get a framebuffer (task framebuffer and GetCanvas both null)."); - let fbinfo = unsafe { - iv.GetTaskFramebufferInfo(iv.GetCurrentTask()) - .as_mut() - .expect("Failed to get current task framebuffer info.") + // Framebuffer info is informational only and task-only; skip it on the + // emulator rather than dereferencing a null pointer. + let fbinfo = if Self::is_emulator(iv) { + None + } else { + unsafe { iv.GetTaskFramebufferInfo(iv.GetCurrentTask()).as_mut() } }; dbg!(fbinfo); From 363c5a2f1c236f08d3e84513380d038ed7c77dc9 Mon Sep 17 00:00:00 2001 From: Alberto Date: Thu, 25 Jun 2026 19:45:05 +0200 Subject: [PATCH 2/2] mr comments --- inkview/src/screen.rs | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/inkview/src/screen.rs b/inkview/src/screen.rs index 3e7f290..f37c072 100644 --- a/inkview/src/screen.rs +++ b/inkview/src/screen.rs @@ -53,23 +53,14 @@ pub struct Screen<'a> { } impl<'a> Screen<'a> { - /// Whether we're running under the desktop SDK emulator rather than on-device. - /// - /// The task-framebuffer API (`GetCurrentTask`/`GetTaskFramebuffer`) is only - /// wired up on-device: the emulator's `GetCurrentTask()` returns -1 (on both - /// the main and worker threads), while the device returns a real task id. - fn is_emulator(iv: &Inkview) -> bool { - unsafe { iv.GetCurrentTask() < 0 } - } - pub fn new(iv: &'a Inkview) -> Self { unsafe { iv.SetCurrentApplicationAttribute(APPLICATION_ATTRIBUTE_APPLICATION_READER, 1); } // On the emulator the task framebuffer is null, so fall back to the global // canvas (GetCanvas) — the same `icanvas_s`, populated in both environments. - // We keep this as a null-check (not gated on `is_emulator`) so it still - // recovers if a real task ever hands back a null framebuffer. + // We do this with a plain null-check so it also recovers if a real task + // ever hands back a null framebuffer. let fb = unsafe { let task_fb = iv.GetTaskFramebuffer(iv.GetCurrentTask()); if task_fb.is_null() { @@ -79,16 +70,6 @@ impl<'a> Screen<'a> { } } .expect("Failed to get a framebuffer (task framebuffer and GetCanvas both null)."); - - // Framebuffer info is informational only and task-only; skip it on the - // emulator rather than dereferencing a null pointer. - let fbinfo = if Self::is_emulator(iv) { - None - } else { - unsafe { iv.GetTaskFramebufferInfo(iv.GetCurrentTask()).as_mut() } - }; - - dbg!(fbinfo); dbg!(fb.depth); let depth = fb.depth;