Dimithrandir
Dimithrandir

Reputation: 46

Segmentation fault when displaying Popover triggered from custom CellRenderer in PyGTK

I created a custom widget inheriting from Gtk.CellRenderer, where I define a custom signal which I emit from the overridden do_active. When I try to show a Gtk.Popover with popup() in the connected handler method for that signal, I get a segmentation fault (core dumped).

The signal seems to work alright, all the data is passed and everything. It's only when I try to show a new widget here that this happens. Creating Popovers works from other methods.

Same thing happens if I try to show Gtk.Dialog, but much less commonly - it happens every other time or so, while with Gtk.Popover it happens 95% of the time.

class MyCellRenderer(Gtk.CellRenderer):

    __gproperties__ = { ... }

    __gsignals__ = {
            'clicked': (
                GObject.SignalFlags.RUN_FIRST,
                None,
                ( ... )
                )
            }

    def __init__(self):
        ...

    def do_activate(self, event, widget, path, background_area, cell_area, flags):
        ...
        self.emit('clicked', path, key, rect)
        ...


class AppWindow(Gtk.ApplicationWindow):

    def __init__(self, application):
        ...
        my_renderer = MyCellRenderer()
        my_renderer.connect('clicked', self.on_renderer_clicked)
        ...
        my_treeview_column = Gtk.TreeViewColumn('My Renderer')
        my_treeview_column.pack_start(my_renderer, True)
        my_treeview_column.add_attribute( ... )
        ...
        self.treeview.append_column(my_treeview_column)
        ...

    
    def on_renderer_clicked(self, *args):

        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
        label = Gtk.Label(label='Example label')
        box.pack_start(label, True, True, 10)
        box.show_all()

        popover = Gtk.Popover()
        popover.add(box)
        popover.set_relative_to(self.treeview)    # any widget would give the same result
        popover.popup()    # segmentation fault happens here
    
    ...


I know this used to work, as I have tested it before. Coming back to the (unmodified) code after some time, I am surprised to see such an issue. Could it be a bug in the newer version of some of the imported modules? If so, which one? Any ideas for troubleshooting?

Upvotes: 0

Views: 77

Answers (1)

Dimithrandir
Dimithrandir

Reputation: 46

Being unable to find the real reason behind the segfault, I had to take a different approach to achieve what I initially wanted. I decided to ditch the custom signal, and instead try to catch events on the Treeview, and from here to then get the information I need.

This might, in fact, be the preferred way of showing Popover widgets over Treeview in PyGtk, but I cannot confirm as I couldn't find any examples of it.

The code from the example above would now look like this:

class MyCellRenderer(Gtk.CellRenderer):

    __gproperties__ = { ... }
    
    def __init__(self):
        ...
    
    # custom signal is removed
    # so is do_activate() as there is no need for CellRenderer to be activatable any more


class AppWindow(Gtk.ApplicationWindow):

    def __init__(self, application):
        ...
        my_renderer = MyCellRenderer()
        # we connect the 'button-press-event' signal now
        my_renderer.connect('button-press-event', self.on_treeview_clicked) 
        ...
        my_treeview_column = Gtk.TreeViewColumn('My Renderer')
        my_treeview_column.pack_start(my_renderer, True)
        my_treeview_column.add_attribute( ... )
        ...
        self.treeview.append_column(my_treeview_column)
        ...

    
    def on_treeview_clicked(self, widget, event):
        # process only left click events
        if event.button == 1:
            # find the path and column at the point of click event
            path, column, cell_x, cell_y = widget.get_path_at_pos(int(event.x), int(event.y))
            # process only valid, selected paths for our desired column (index 1 in this example)
            if path is not None and column == widget.get_column(1) and widget.get_selection().path_is_selected(path):
                # get coordinates for clicked cell
                cell_area = widget.get_cell_area(path, column)

                box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
                label = Gtk.Label(label='Example label')
                box.pack_start(label, True, True, 10)
                box.show_all()

                popover = Gtk.Popover()
                popover.add(box)
                popover.set_relative_to(widget)
                # set popover to point to clicked cell
                popover.set_pointing_to(cell_area)
                popover.popup()
    
    ...

Upvotes: 0

Related Questions