mirror of
https://github.com/gnuradio/gnuradio-companion.git
synced 2025-12-10 15:57:35 -06:00
grc: Fix cairo assertion failure by not storing reference to context.
The connection flowgraph element previously kept a reference to the cairo context passed to the draw function in order to be able to use cairo's `in_stroke` function to determine if the mouse cursor was on the path of the curved connection line. As it turns out, this is dangerous because GTK is constantly destroying and creating new cairo contexts and surfaces. This avoids keeping a reference to the cairo context by initializing a local cairo context with the connection class for the sole purpose of storing the curved path and calculating `in_stroke`. The local context and surface can be very basic because not much is needed for `in_stroke`, and the context can persist and just have its path replaced when it needs to be updated. On Windows, resizing the GRC window (and particularly the flowgraph canvas) to a larger size than its initial size would cause the underlying cairo surface to be destroyed and a new one created. The cairo context stored for the curved connection line had a reference to that destroyed surface, and closing that context (upon replacing it with a new one) would attempt decrement the reference count on the surface. This would produce an assertion failure that crashed GRC stating `Assertion failed: CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count)`. On macOS with the Quartz backend, a related crash and assertion error would manifest when connecting blocks. Signed-off-by: Ryan Volz <ryan.volz@gmail.com>
This commit is contained in:
parent
32fa6b4e0a
commit
a1288a8f3f
@ -10,6 +10,8 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
||||
from argparse import Namespace
|
||||
from math import pi
|
||||
|
||||
import cairo
|
||||
|
||||
from . import colors
|
||||
from .drawable import Drawable
|
||||
from .. import Utils
|
||||
@ -45,8 +47,11 @@ class Connection(CoreConnection, Drawable):
|
||||
|
||||
self._rel_points = None # connection coordinates relative to sink/source
|
||||
self._arrow_rotation = 0.0 # rotation of the arrow in radians
|
||||
self._current_cr = None # for what_is_selected() of curved line
|
||||
self._line_path = None
|
||||
# simple cairo context for curved line and computing what_is_selected
|
||||
cr = cairo.Context(cairo.RecordingSurface(cairo.CONTENT_ALPHA, None))
|
||||
cr.set_line_width(cr.get_line_width() * LINE_SELECT_SENSITIVITY)
|
||||
self._line_path_cr = cr
|
||||
|
||||
@nop_write
|
||||
@property
|
||||
@ -125,12 +130,13 @@ class Connection(CoreConnection, Drawable):
|
||||
cr.curve_to(*(p2 + p3 + p4))
|
||||
cr.line_to(*p5)
|
||||
self._line_path = cr.copy_path()
|
||||
self._line_path_cr.new_path()
|
||||
self._line_path_cr.append_path(self._line_path)
|
||||
|
||||
def draw(self, cr):
|
||||
"""
|
||||
Draw the connection.
|
||||
"""
|
||||
self._current_cr = cr
|
||||
sink = self.sink_port
|
||||
source = self.source_port
|
||||
|
||||
@ -192,18 +198,11 @@ class Connection(CoreConnection, Drawable):
|
||||
if coor_m:
|
||||
return Drawable.what_is_selected(self, coor, coor_m)
|
||||
|
||||
x, y = [a - b for a, b in zip(coor, self.coordinate)]
|
||||
|
||||
cr = self._current_cr
|
||||
|
||||
if cr is None:
|
||||
if self._line_path is None:
|
||||
return
|
||||
cr.save()
|
||||
cr.new_path()
|
||||
cr.append_path(self._line_path)
|
||||
cr.set_line_width(cr.get_line_width() * LINE_SELECT_SENSITIVITY)
|
||||
hit = cr.in_stroke(x, y)
|
||||
cr.restore()
|
||||
|
||||
x, y = [a - b for a, b in zip(coor, self.coordinate)]
|
||||
hit = self._line_path_cr.in_stroke(x, y)
|
||||
|
||||
if hit:
|
||||
return self
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user