fix(gtk4): derive the device-pixel factor from GTK's two sizes, and four more review fixes
The factor both the viewport and every forwarded input coordinate use came from `gtk_widget_get_scale_factor()`, which GTK documents as "the next higher integer value" under fractional scaling. It is now derived by `DeviceMapping::from_sizes()` from the widget's logical allocation and the device size `GtkGLArea::resize` reports -- the viewport that signal's default handler sets with `glViewport(0, 0, w, h)` -- so the viewport, the renderer and input are one value by construction. The public `int scale_factor()` became `f32 device_scale()`. `kSurfacePixelsPerNotch` is now 100.0 and documented as a *calibration* with a stated assumption, not a unit conversion attributed to axis_value120/Qt. `::unrealize` releases the renderer unconditionally, after making the context current: the error it used to check says nothing about whether GL names exist (creation failure is the path that returns before a renderer is built), and skipping the release left the deletes to the wrapper's destructor, with no context. The drag anchor caches its press point and offsets in logical pixels and scales the difference by the factor in force now, so a scale change mid-drag cannot become a phantom pan. The demo stops its producer in `on_teardown`, before destroying the window whose renderer the stream feeds.
This commit is contained in:
1 parent
36cd3421f3
commit
0445a1861b
6 files changed
+417
-137
No files matched your search
+15
-7
@@ -76,7 +76,8 @@ constexpr plot::Color kTraceColor = plot::Color::hex(0x40C0FF);
|
||||
constexpr plot::Color kCursorAColor = plot::Color::hex(0xFFB020);
|
||||
constexpr plot::Color kCursorBColor = plot::Color::hex(0x35D0A8);
|
||||
|
||||
/// Logical pixels. The area's framebuffer is `scale_factor` times this.
|
||||
/// Logical pixels. The area's framebuffer -- the area's GL viewport -- is in
|
||||
/// device pixels.
|
||||
constexpr int kWindowWidth = 1200;
|
||||
constexpr int kWindowHeight = 800;
|
||||
/// The size the scripted resize before the exit frame goes to: different on both
|
||||
@@ -304,6 +305,11 @@ void capture_snapshot(Demo& demo) {
|
||||
/// `on_render_after`.
|
||||
gboolean on_teardown(gpointer user_data) {
|
||||
Demo& demo = *static_cast<Demo*>(user_data);
|
||||
// The producer is joined *first*, while the widget and the stream it feeds are
|
||||
// both still alive: the join is what makes "no thread pushes into the stream
|
||||
// after this point" true for the destruction below, and for the frames the
|
||||
// widget may still stage while it is being torn down.
|
||||
demo.producer->stop();
|
||||
// Destroyed explicitly rather than left to the application's shutdown, so an
|
||||
// automated run exercises the widget's teardown -- the renderer's GL objects are
|
||||
// released in `::unrealize`, with the context still current -- and a fault in it
|
||||
@@ -394,10 +400,10 @@ gboolean on_exit_timer(gpointer user_data) {
|
||||
// the strip with it.
|
||||
const bool recomputed = after.axes.w != before.axes.w && after.axes.x == before.axes.x;
|
||||
std::printf("\n[gtk_demo] ---- exit frame ----\n");
|
||||
std::printf("[gtk_demo] resize logical %dx%d -> %dx%d, device viewport %ux%u, scale %d\n",
|
||||
std::printf("[gtk_demo] resize logical %dx%d -> %dx%d, device viewport %ux%u, scale %g\n",
|
||||
width_before, height_before, gtk_widget_get_width(demo.area->widget()),
|
||||
gtk_widget_get_height(demo.area->widget()), static_cast<unsigned>(viewport.w),
|
||||
static_cast<unsigned>(viewport.h), demo.area->scale_factor());
|
||||
static_cast<unsigned>(viewport.h), static_cast<double>(demo.area->device_scale()));
|
||||
std::printf("[gtk_demo] layout axes %.0fx%.0f at (%.0f,%.0f) -> %.0fx%.0f at (%.0f,%.0f): %s\n",
|
||||
static_cast<double>(before.axes.w), static_cast<double>(before.axes.h),
|
||||
static_cast<double>(before.axes.x), static_cast<double>(before.axes.y),
|
||||
@@ -483,11 +489,12 @@ void on_activate(GtkApplication* app, gpointer user_data) {
|
||||
const plot::Rect axes = std::as_const(p).layout().axes;
|
||||
const plot::Range xr = p.x_range(demo.axis_x);
|
||||
std::printf(
|
||||
"[gtk_demo] t=%.1fs %.3f MS/s %.2f ms/frame scale %d fbo %ux%u axes %.0fx%.0f"
|
||||
"[gtk_demo] t=%.1fs %.3f MS/s %.2f ms/frame scale %g fbo %ux%u axes %.0fx%.0f"
|
||||
" x [%.6f, %.6f] span %.6f auto %d %llu frames\n",
|
||||
demo.meter.elapsed, demo.meter.rate * 1.0e-6,
|
||||
static_cast<double>(demo.area->mean_frame_ms()), demo.area->scale_factor(),
|
||||
static_cast<unsigned>(viewport.w), static_cast<unsigned>(viewport.h),
|
||||
static_cast<double>(demo.area->mean_frame_ms()),
|
||||
static_cast<double>(demo.area->device_scale()), static_cast<unsigned>(viewport.w),
|
||||
static_cast<unsigned>(viewport.h),
|
||||
static_cast<double>(axes.w), static_cast<double>(axes.h), xr.min, xr.max, xr.span(),
|
||||
p.x_axis(demo.axis_x).auto_scale ? 1 : 0,
|
||||
static_cast<unsigned long long>(demo.meter.frames));
|
||||
@@ -592,7 +599,8 @@ int main(int argc, char** argv) {
|
||||
|
||||
// The window is gone by now -- `on_render_after` destroyed it before quitting --
|
||||
// so only what the demo owns is read below.
|
||||
producer.stop(); // no thread pushes into the stream after this point
|
||||
producer.stop(); // already stopped by on_teardown; idempotent, and this is the
|
||||
// path a window closed by hand takes (no on_teardown then)
|
||||
|
||||
print_summary(demo);
|
||||
std::printf("[gtk_demo] teardown the area widget is %s after the main loop\n",
|
||||
|
||||
Reference in new issue
Block a user