From 506a6386d974946c57c9fa2ac7b0a5bb183f18e4 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Mon, 4 Mar 2024 23:39:28 -0500 Subject: [PATCH] Fix fan charts on HiDPI screens Most DrawingArea-based widgets are fine, but the fan charts use a backing image surface that is blitted when needed. On HiDPI displays, this image surface is normal size, and thus everything ends up blurry when scaled up. Instead the backing surface should be scaled to match the display, and also re-created if the display scale changes (e.g., if display settings change, or the window is moved between displays with different settings.) --- gramps/gui/widgets/fanchart.py | 20 +++++++++++++++++++- gramps/gui/widgets/fanchart2way.py | 6 +++++- gramps/gui/widgets/fanchartdesc.py | 6 +++++- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/gramps/gui/widgets/fanchart.py b/gramps/gui/widgets/fanchart.py index f0390b83b69..5e371ac5b19 100644 --- a/gramps/gui/widgets/fanchart.py +++ b/gramps/gui/widgets/fanchart.py @@ -165,6 +165,7 @@ def __init__(self, dbstate, uistate, callback_popup=None): self.set_can_focus(True) self.connect("key-press-event", self.on_key_press) + self.connect("notify::scale-factor", self.on_notify_scale_factor) self.connect("draw", self.on_draw) self.add_events( Gdk.EventMask.BUTTON_PRESS_MASK @@ -295,6 +296,19 @@ def get_radiusinout_for_gen(self, generation): """ raise NotImplementedError + def on_notify_scale_factor(self, obj, pspec): + """ + Callback to redraw the fanchart if the display's scale factor changes. + """ + if not self.surface: + return + existing_scale = self.surface.get_device_scale() + if self.get_scale_factor() == existing_scale[0] == existing_scale[1]: + return + self.surface = None + self.draw() + self.queue_draw() + def on_draw(self, widget, ctx, scale=1.0): """ callback to draw the fanchart @@ -1676,7 +1690,11 @@ def draw(self, ctx=None, scale=1.0): self.set_size_request(max(size_w, size_w_a), max(size_h, size_h_a)) size_w = self.get_allocated_width() size_h = self.get_allocated_height() - self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, size_w, size_h) + scale_factor = self.get_scale_factor() + self.surface = cairo.ImageSurface( + cairo.FORMAT_ARGB32, size_w * scale_factor, size_h * scale_factor + ) + self.surface.set_device_scale(scale_factor, scale_factor) ctx = cairo.Context(self.surface) self.center_xy = self.center_xy_from_delta() ctx.translate(*self.center_xy) diff --git a/gramps/gui/widgets/fanchart2way.py b/gramps/gui/widgets/fanchart2way.py index fda9b350f84..4120e4bc549 100644 --- a/gramps/gui/widgets/fanchart2way.py +++ b/gramps/gui/widgets/fanchart2way.py @@ -463,7 +463,11 @@ def draw(self, ctx=None, scale=1.0): self.set_size_request(max(size_w, size_w_a), max(size_h, size_h_a)) size_w = self.get_allocated_width() size_h = self.get_allocated_height() - self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, size_w, size_h) + scale_factor = self.get_scale_factor() + self.surface = cairo.ImageSurface( + cairo.FORMAT_ARGB32, size_w * scale_factor, size_h * scale_factor + ) + self.surface.set_device_scale(scale_factor, scale_factor) ctx = cairo.Context(self.surface) self.center_xy = self.center_xy_from_delta() ctx.translate(*self.center_xy) diff --git a/gramps/gui/widgets/fanchartdesc.py b/gramps/gui/widgets/fanchartdesc.py index 00d5b9f360e..3881829a60f 100644 --- a/gramps/gui/widgets/fanchartdesc.py +++ b/gramps/gui/widgets/fanchartdesc.py @@ -491,7 +491,11 @@ def draw(self, ctx=None, scale=1.0): self.set_size_request(max(size_w, size_w_a), max(size_h, size_h_a)) size_w = self.get_allocated_width() size_h = self.get_allocated_height() - self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, size_w, size_h) + scale_factor = self.get_scale_factor() + self.surface = cairo.ImageSurface( + cairo.FORMAT_ARGB32, size_w * scale_factor, size_h * scale_factor + ) + self.surface.set_device_scale(scale_factor, scale_factor) ctx = cairo.Context(self.surface) self.center_xy = self.center_xy_from_delta() ctx.translate(*self.center_xy)