After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 447271 - gobject has a weird bug on mac. Involves python, property and subclassing gtk.Widget
gobject has a weird bug on mac. Involves python, property and subclassing gtk...
Status: RESOLVED FIXED
Product: pygobject
Classification: Bindings
Component: general
2.13.x
Other All
: Normal critical
: ---
Assigned To: Nobody's working on this now (help wanted and appreciated)
Python bindings maintainers
Depends on:
Blocks:
 
 
Reported: 2007-06-13 18:47 UTC by Guilherme Polo
Modified: 2007-06-17 16:26 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
minimal test case (266 bytes, text/plain)
2007-06-17 15:39 UTC, Gustavo Carneiro
Details

Description Guilherme Polo 2007-06-13 18:47:04 UTC
Steps to reproduce:
1. sublcass gtk.Widget to create two minimal widgets
2. in one of the widgets, create a property
3. gobject.type_register them
4. create an instance for both widgets
5. pass widget B as the parameter to property in widget A
6. run it and watch it crash, mac only!


Stack trace:
python umitInventory/new-sample/tests/test666b2.py

GLib-GObject-ERROR **: file gobject.c: line 1625 (toggle_refs_notify): assertion failed: (tstack->n_toggle_refs == 1)
aborting...
Abort trap

Other information:
minimal sample:

import gtk
import gobject

from gtk import gdk

class A(gtk.Widget):
    def __init__(self):
        gtk.Widget.__init__(self)

    def _get_color(self):
        return self.__color

    def _set_color(self, color):
        self.__color = color

    def do_realize(self):
        self.set_flags(self.flags() | gtk.REALIZED)

        self.window = gdk.Window(self.get_parent_window(),
                                 width=self.allocation.width,
                                 height=self.allocation.height,
                                 window_type=gdk.WINDOW_CHILD,
                                 wclass=gdk.INPUT_OUTPUT,
                                 event_mask=self.get_events() | 
                                            gdk.EXPOSURE_MASK)

        self.window.set_user_data(self)
        self.style.attach(self.window)
        self.style.set_background(self.window, gtk.STATE_NORMAL)
        self.window.move_resize(*self.allocation)

    def do_unrealize(self):
        self.window.set_user_data(None)

    def do_size_request(self, requisition):
        requisition.width = 40
        requisition.height = 100

    def do_size_allocate(self, allocation):
        self.allocation = allocation

        if self.flags() & gtk.REALIZED:
            self.window.move_resize(*allocation)

    def do_expose_event(self, event):
        cr = self.window.cairo_create()
        cr.rectangle(*event.area)
        cr.clip()

        cr.rectangle(*event.area)
        cr.set_source_rgb(1, 1, 0)
        cr.fill()

    badprop = property(_get_color, _set_color)

gobject.type_register(A)


class B(gtk.Widget):
    def __init__(self):
        gtk.Widget.__init__(self)

    def do_realize(self):
        self.set_flags(self.flags() | gtk.REALIZED)

        self.window = gdk.Window(self.get_parent_window(),
                                 width=self.allocation.width,
                                 height=self.allocation.height,
                                 window_type=gdk.WINDOW_CHILD,
                                 wclass=gdk.INPUT_OUTPUT,
                                 event_mask=self.get_events() | 
                                            gdk.EXPOSURE_MASK)

        self.window.set_user_data(self)
        self.style.attach(self.window)
        self.style.set_background(self.window, gtk.STATE_NORMAL)
        self.window.move_resize(*self.allocation)

    def do_unrealize(self):
        self.window.set_user_data(None)

    def do_size_request(self, requisition):
        requisition.width = 100
        requisition.height = 100

    def do_size_allocate(self, allocation):
        self.allocation = allocation

        if self.flags() & gtk.REALIZED:
            self.window.move_resize(*allocation)

    def do_expose_event(self, event):
        cr = self.window.cairo_create()
        cr.rectangle(*event.area)
        cr.clip()

        cr.rectangle(*event.area)
        cr.stroke()

gobject.type_register(B)


class win(gtk.Window):
    def __init__(self):
        gtk.Window.__init__(self)

        box = gtk.HBox()
        a = A()
        b = B()
        a.badprop = b

        box.add(b)
        box.add(a)
        
        self.add(box)

        self.connect('delete-event', lambda x,y:gtk.main_quit())


if __name__ == "__main__":
    w = win()
    w.show_all()
    gtk.main()
Comment 1 Gustavo Carneiro 2007-06-17 14:43:15 UTC
Not Mac specific.  Likely PyGObject bug.
Comment 2 Gustavo Carneiro 2007-06-17 15:39:23 UTC
Created attachment 90148 [details]
minimal test case

The problem is that pygobject_switch_to_toggle_ref is being called twice, both times from pygobject_setattro.  It happens because in this case pygobject_setattro  ends up recursively calling itself, and both the inner and outer pygobject_setattro invocations see the instance dictionary being created and call pygobject_switch_to_toggle_ref.
Comment 3 Gustavo Carneiro 2007-06-17 16:26:56 UTC
Committed revision 677.