mirror of
https://github.com/storytold/photocraft.git
synced 2026-10-24 09:57:08 -06:00
* fix(picker): the screen color picker no longer crashes on DX12 or traps the overlay on Windows (#4443) Two Windows-only faults in the Pick screen color window: - Created always-on-top, the monitor-sized picker window makes the DX12 backend fail swapchain creation (0x887A0001, DXGI_ERROR_INVALID_CALL); wgpu then panics in Surface::get_current_texture_view. The window is now created at the normal level and raised once its first frame is painted. - As a deferred viewport the picker was painted on its own, and the main window stopped being redrawn while it was up on Windows (OpenGL). A click or Esc only stored an answer that the main window's tick() never took, so the overlay could not be left. It is now an immediate viewport, painted inside the main window's frame. Verified on Windows 11 / Intel UHD 630: DX12 (default) opens, picks and cancels; OpenGL picks and cancels; macOS still picks and cancels. Adds a test that the picker viewport is not built always-on-top. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * Screen picker: raise the window level once per picker window, not every frame Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
Brandon Thomas
parent
715f4fd397
commit
9cba6a66d8
@@ -259,7 +259,9 @@ fn viewport_builder(ctx: &Context, image: &ScreenImage) -> egui::ViewportBuilder
|
||||
.with_resizable(false)
|
||||
.with_position(image.position / ctx.zoom_factor())
|
||||
.with_inner_size(image.size / ctx.zoom_factor())
|
||||
.with_window_level(egui::WindowLevel::AlwaysOnTop)
|
||||
// Not `AlwaysOnTop` here: a monitor-sized window created topmost makes the DX12 backend
|
||||
// fail its swapchain creation (0x887A0001) and the app panics. The level is raised once
|
||||
// the first frame has been painted, in `show`.
|
||||
// Do not expose the native window's empty first frame over the desktop.
|
||||
// The viewport is made visible after its snapshot has been painted below.
|
||||
.with_visible(false)
|
||||
@@ -280,7 +282,10 @@ pub fn show(ctx: &Context) {
|
||||
let shared = r.clone();
|
||||
let vid = egui::ViewportId::from_hash_of(("screen-color", generation, n));
|
||||
let builder = viewport_builder(ctx, &image);
|
||||
ctx.show_viewport_deferred(vid, builder, move |ui, _| {
|
||||
// Immediate, so it paints inside the main window's own frame: as a deferred viewport the
|
||||
// main window stopped being redrawn on Windows (OpenGL) once the picker was up, so a click
|
||||
// or Esc was never turned into an answer and the overlay could not be left.
|
||||
ctx.show_viewport_immediate(vid, builder, move |ui, _| {
|
||||
{
|
||||
let s = lock(&shared);
|
||||
if s.generation != generation || s.owner.is_none() {
|
||||
@@ -334,6 +339,11 @@ pub fn show(ctx: &Context) {
|
||||
// Showing a new native viewport before this frame is painted can briefly cover
|
||||
// the screen with the window's default white clear color.
|
||||
ui.ctx().send_viewport_cmd(egui::ViewportCommand::Visible(true));
|
||||
// Once per picker window: `show` runs every frame, so a local flag would resend it.
|
||||
let raised = Id::new(("screen-picker-raised", ui.ctx().viewport_id()));
|
||||
if !ui.ctx().data_mut(|d| std::mem::replace(d.get_temp_mut_or_default::<bool>(raised), true)) {
|
||||
ui.ctx().send_viewport_cmd(egui::ViewportCommand::WindowLevel(egui::WindowLevel::AlwaysOnTop));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -393,6 +403,12 @@ mod tests {
|
||||
assert_eq!(builder.visible, Some(false));
|
||||
}
|
||||
#[test]
|
||||
fn screen_picker_viewport_is_not_created_always_on_top() {
|
||||
// Creating the monitor-sized window topmost fails DX12 swapchain creation (Windows).
|
||||
let builder = viewport_builder(&Context::default(), &image());
|
||||
assert_eq!(builder.window_level, None);
|
||||
}
|
||||
#[test]
|
||||
fn pixel_mapping_handles_display_edges_negative_origins_and_hidpi() {
|
||||
let i = image();
|
||||
let rect = Rect::from_min_size(i.position, i.size);
|
||||
|
||||
Reference in New Issue
Block a user