Discussion:
callback strangeness?
Cees de Groot
2006-07-19 15:18:01 UTC
Permalink
Hi,

I had:

WxListCtrl
DGVFileListCtrl

I wanted:

WxListCtrl
DGVListCtrl
DGVFileListCtrl
DGVUserListCtrl

So I set out with the RB to push up from the file list all that was
possible. Now, when I push up methods like onGetItemText:count: and then
test my app I get wx assertions that say that virtual functions where
called that aren't supposed to be called around the C++ side of
onGetItemText handling. Push down again, assertions go.

Is there some strangeness related to looking up where a callback should
land at the Squeak side of life?

Regards,

Cees
Rob Gayvert
2006-07-19 15:18:01 UTC
Permalink
Post by Cees de Groot
Hi,
WxListCtrl
DGVFileListCtrl
WxListCtrl
DGVListCtrl
DGVFileListCtrl
DGVUserListCtrl
So I set out with the RB to push up from the file list all that was
possible. Now, when I push up methods like onGetItemText:count: and
then test my app I get wx assertions that say that virtual functions
where called that aren't supposed to be called around the C++ side
of onGetItemText handling. Push down again, assertions go.
Is there some strangeness related to looking up where a callback
should land at the Squeak side of life?
Yep, just a bug in telling the underlying C++ object which callbacks the
Squeak object supports, in the case of a subclass more than one level
removed from the "concrete" class (in this instance, WxListCtrl). I
think this patch should fix it. Let me know how it works for you.

.. Rob

-------------- next part --------------
'From Squeak3.7 of ''4 September 2004'' [latest update: #5989] on 15 March 2005 at 7:58:04 am'!
!WxBase methodsFor: 'as yet unclassified' stamp: 'rtg 3/15/2005 07:47'!
setCallbackFlags

"Determine which callbacks are implemented by my class. IMPORTANT NOTE: flags are ordered
by method name alphabetically."

| cm md flags flag cls |

"use only if this class has an underlying sqWxXXX class"
cm := WxGenericCallback callbackMethodsFor: self class.
cm ifNil: [ ^self ].

cls := self class.
flags := 0.

"Look for callback selectors up to the first concrete wx class."
[cls notNil and: [ (cls class includesSelector: #callbackMethods) not ]] whileTrue: [
md := cls methodDictionary.
flag := 1.
cm keys asSortedCollection do: [:selector |
(md includesKey: selector)
ifTrue: [ flags := flags bitOr: flag ].
flag := flag bitShift: 1.
].
cls := cls superclass.
].

(Wx debugCallbacks & (flags ~= 0))
ifTrue: [ Wx debug: 'setCallbackFlags: obj=', self asString, ', flags=', flags asString ].

flags = 0 ifFalse: [ self setCallbackFlags: flags ].

^flags! !
!WxControl class methodsFor: 'as yet unclassified' stamp: 'rtg 3/15/2005 07:47'!
callbackMethods

^#()! !
!WxMenuBar class methodsFor: 'as yet unclassified' stamp: 'rtg 3/15/2005 07:48'!
callbackMethods

^#()! !
!WxPanel class methodsFor: 'as yet unclassified' stamp: 'rtg 3/15/2005 07:49'!
callbackMethods

^#()! !
!WxPopupWindow class methodsFor: 'as yet unclassified' stamp: 'rtg 3/15/2005 07:49'!
callbackMethods

^#()! !
!WxSashWindow class methodsFor: 'as yet unclassified' stamp: 'rtg 3/15/2005 07:49'!
callbackMethods

^#()! !
!WxSplitterWindow class methodsFor: 'as yet unclassified' stamp: 'rtg 3/15/2005 07:49'!
callbackMethods

^#()! !
!WxStatusBar class methodsFor: 'as yet unclassified' stamp: 'rtg 3/15/2005 07:50'!
callbackMethods

^#()! !
!WxTipWindow class methodsFor: 'as yet unclassified' stamp: 'rtg 3/15/2005 07:50'!
callbackMethods

^#()! !
Rob Gayvert
2006-07-19 15:18:01 UTC
Permalink
Sorry, ignore that last so-called fix. Here's one that has a better
chance of working.
-------------- next part --------------
'From Squeak3.7 of ''4 September 2004'' [latest update: #5989] on 15 March 2005 at 7:58:04 am'!
!WxBase methodsFor: 'as yet unclassified' stamp: 'rtg 3/15/2005 07:47'!
setCallbackFlags

"Determine which callbacks are implemented by my class. IMPORTANT NOTE: flags are ordered
by method name alphabetically."

| cm md flags flag cls |

"use only if this class has an underlying sqWxXXX class"
cm := WxGenericCallback callbackMethodsFor: self class.
cm ifNil: [ ^self ].

cls := self class.
flags := 0.

"Look for callback selectors up to the first concrete wx class."
[cls notNil and: [ (cls class includesSelector: #callbackMethods) not ]] whileTrue: [
md := cls methodDictionary.
flag := 1.
cm keys asSortedCollection do: [:selector |
(md includesKey: selector)
ifTrue: [ flags := flags bitOr: flag ].
flag := flag bitShift: 1.
].
cls := cls superclass.
].

(Wx debugCallbacks & (flags ~= 0))
ifTrue: [ Wx debug: 'setCallbackFlags: obj=', self asString, ', flags=', flags asString ].

flags = 0 ifFalse: [ self setCallbackFlags: flags ].

^flags! !
!WxControl class methodsFor: 'as yet unclassified' stamp: 'rtg 3/15/2005 07:47'!
callbackMethods

^Dictionary new! !
!WxMenuBar class methodsFor: 'as yet unclassified' stamp: 'rtg 3/15/2005 07:48'!
callbackMethods

^Dictionary new! !
!WxPanel class methodsFor: 'as yet unclassified' stamp: 'rtg 3/15/2005 07:49'!
callbackMethods

^Dictionary new! !
!WxPopupWindow class methodsFor: 'as yet unclassified' stamp: 'rtg 3/15/2005 07:49'!
callbackMethods

^Dictionary new! !
!WxSashWindow class methodsFor: 'as yet unclassified' stamp: 'rtg 3/15/2005 07:49'!
callbackMethods

^Dictionary new! !
!WxSplitterWindow class methodsFor: 'as yet unclassified' stamp: 'rtg 3/15/2005 07:49'!
callbackMethods

^Dictionary new! !
!WxStatusBar class methodsFor: 'as yet unclassified' stamp: 'rtg 3/15/2005 07:50'!
callbackMethods

^Dictionary new! !
!WxTipWindow class methodsFor: 'as yet unclassified' stamp: 'rtg 3/15/2005 07:50'!
callbackMethods

^Dictionary new! !

WxGenericCallback initializeCallbacks!
Cees de Groot
2006-07-19 15:18:01 UTC
Permalink
Post by Rob Gayvert
Sorry, ignore that last so-called fix. Here's one that has a better
chance of working.
Heh - just after responding in private mail I got the thing again. But now
on my 'regular' pluggable list, which is a direct subclass of the
WxListCtrl. I'll file your patch in and report back whether this makes a
difference (I'm currently probably stretching some limits in dynamic UI
creation, adding and removing tree nodes, creating wxnotebook panes on the
fly, etcetera ;)).
Cees de Groot
2006-07-19 15:18:01 UTC
Permalink
Post by Rob Gayvert
Sorry, ignore that last so-called fix. Here's one that has a better
chance of working.
Still get the (new) instance of the error. At least - it looks like the
same error, with the virtual function being called etcetera. I'll look
through my code whether I've done anything funny...
Cees de Groot
2006-07-19 15:18:01 UTC
Permalink
Ok, what I just found out (probably the last bit for a while...) is that
this happens when I add an item to the list while I am looking at it
'through' a WxListCtrl (or better, my pluggable descendant of it).

The code in question shows the results of a p2p search. Items are slowly
dripping in. I start the search, then navigate to the list which shows one
found item. Then I wait a bit, move the mouse - a second hit shows up
(refresh issue?) and immediately afterwards the assert triggers and the
whole thing crashes and burns (it hits on a nested/re-enterered assert()
so it really barfs instead of just politlely popping up the wx assert
dialog).
Rob Gayvert
2006-07-19 15:18:01 UTC
Permalink
Post by Cees de Groot
Ok, what I just found out (probably the last bit for a while...) is
that this happens when I add an item to the list while I am looking
at it 'through' a WxListCtrl (or better, my pluggable descendant of it).
The code in question shows the results of a p2p search. Items are
slowly dripping in. I start the search, then navigate to the list
which shows one found item. Then I wait a bit, move the mouse - a
second hit shows up (refresh issue?) and immediately afterwards the
assert triggers and the whole thing crashes and burns (it hits on a
nested/re-enterered assert() so it really barfs instead of just
politlely popping up the wx assert dialog).
Hmm, this sounds like a different problem. To verify that it's not a
problem with #setCallbackFlags, try setting "Wx debugCallbacks: true".
This will write some callback detail to the file wxsqueak.log. If you
see a line with "...setCallbackFlags...<your class>...flags=0" then
there is still a problem. If the flags are not zero, the problem is
likely elsewhere.
Cees de Groot
2006-07-19 15:18:01 UTC
Permalink
Post by Rob Gayvert
Hmm, this sounds like a different problem. To verify that it's not a
problem with #setCallbackFlags, try setting "Wx debugCallbacks: true".
This will write some callback detail to the file wxsqueak.log. If you
see a line with "...setCallbackFlags...<your class>...flags=0" then
there is still a problem. If the flags are not zero, the problem is
likely elsewhere.
Nothing like that. The lines are all like:

18:39:02: : wxGenericCallback, cls=WxListCtrl, method=onGetItemImage:,
type=0
18:39:02: : callback: cls=WxListCtrl, selector=onGetItemImage:
18:39:02: : callback argTypes: #(WxListCtrl SmallInteger)
18:39:02: : callback: args=#(DGVPluggableList[16r14A6A18] 1)
18:39:02: : wxGenericCallback, cls=WxListCtrl, method=onGetItemAttr:,
type=24
18:39:02: : callback: cls=WxListCtrl, selector=onGetItemAttr:
18:39:02: : callback argTypes: #(WxListCtrl SmallInteger)
18:39:02: : callback: args=#(DGVPluggableList[16r14A6A18] 2)

However, I just realized that the p2p search sends global references, not
actual objects, in some cases. Reference resolution times out after two
seconds, so that could be the cause of this. I'll investigate more...
Cees de Groot
2006-07-19 15:18:01 UTC
Permalink
Post by Cees de Groot
However, I just realized that the p2p search sends global references,
not actual objects, in some cases. Reference resolution times out after
two seconds, so that could be the cause of this. I'll investigate more...
Yup. That's it. I paint different icons in the list, the test needs to
resolve a global network link to see what icon needs to be returned. So
the #onGetItemImage: callback takes around 2 seconds. This seems to
severely mess up everything else (which, IMHO, means that there are still
some holes in the call back handling - whether the callback takes 2
nanoseconds or 2 years should not make a difference in how wxSqueak works,
should it?)

Oh well, not much I can do to that for now, can I?
Rob Gayvert
2006-07-19 15:18:01 UTC
Permalink
Post by Cees de Groot
Post by Cees de Groot
However, I just realized that the p2p search sends global
references, not actual objects, in some cases. Reference resolution
times out after two seconds, so that could be the cause of this.
I'll investigate more...
Yup. That's it. I paint different icons in the list, the test needs
to resolve a global network link to see what icon needs to be
returned. So the #onGetItemImage: callback takes around 2 seconds.
This seems to severely mess up everything else (which, IMHO, means
that there are still some holes in the call back handling - whether
the callback takes 2 nanoseconds or 2 years should not make a
difference in how wxSqueak works, should it?)
Oh well, not much I can do to that for now, can I?
With a virtual list control, #onGetItemImage: get called once for each
item in the list each time that the list is displayed, so if the
callback takes a significant amount of time this is going to make the
GUI very unresponsive. I think you'd be much better off with some kind
of asynchronous update to the list.

That's not to say that the callback handling doesn't have holes, because
it does ;) But even after we get it plugged, it will be a good policy
to keep callbacks as short as possible to make the UI feel fast.
Cees de Groot
2006-07-19 15:18:01 UTC
Permalink
Post by Rob Gayvert
With a virtual list control, #onGetItemImage: get called once for each
item in the list each time that the list is displayed, so if the
callback takes a significant amount of time this is going to make the
GUI very unresponsive. I think you'd be much better off with some kind
of asynchronous update to the list.
Yup. However, this is just the single list where network-wide search
results are displayed. Furthermore, in this particular case, the callback
took time because the network didn't return any results (it tries for 2
seconds) which indicates some data inconsistencies (IOW: shouldn't happen
in Real Life, at least not regularly).

But performance/responsiveness aside, any idea what causes the crash&burn?
Rob Gayvert
2006-07-19 15:18:01 UTC
Permalink
On Tue, 15 Mar 2005 14:53:52 -0500, Rob Gayvert
Post by Rob Gayvert
With a virtual list control, #onGetItemImage: get called once for
each item in the list each time that the list is displayed, so if
the callback takes a significant amount of time this is going to
make the GUI very unresponsive. I think you'd be much better off
with some kind of asynchronous update to the list.
Yup. However, this is just the single list where network-wide search
results are displayed. Furthermore, in this particular case, the
callback took time because the network didn't return any results (it
shouldn't happen in Real Life, at least not regularly).
But performance/responsiveness aside, any idea what causes the
crash&burn?
I suspect it's the same deal as with more innocuous glitches (like
wxGetResult returning a nil value) amplified by the long delay. The
current callback scheme is far too dependent on process priorities and
timing. When it crashes like this, it's very difficult to trace what has
gone wrong. If I can't resolve it soon, I'm going to look at running the
interpreter in a separate thread.
Cees de Groot
2006-07-19 15:18:01 UTC
Permalink
If I can't resolve it soon, I'm going to look at running the interpreter
in a separate thread.
That'll probably open a whole fresh can of worms...

I didn't really follow your discussion with Andreas, because it was a bit
over my head - it didn't bring anything to light, did it?
Andreas Raab
2006-07-19 15:18:01 UTC
Permalink
Post by Cees de Groot
I didn't really follow your discussion with Andreas, because it was a
bit over my head - it didn't bring anything to light, did it?
Actually it did, I just got stuck with the conclusion. What happens is
that the VM must be in a "sane state" for callbacks to work
appropriately. That sane state is reached when we're in a primitive but
not anyplace else. If a callback occurs in an unsane state then the
internals of the VM get horribly messed up and Many Bad Things start to
happen.

It would probably be best to change the VM to provide the required
information implicitly or explicitly. For example, if we would make it
so that after primitiveResponse() the primitiveIndex is reset to zero,
then we could do The Right Thing in ioProcessEvents() - at worst we just
bail if invoked with "primitiveIndex == 0".

Cheers,
- Andreas

Cees de Groot
2006-07-19 15:18:01 UTC
Permalink
Last 'report' - it's not the asynchronous updating. But it suspiciously
looks like it...

The search quickly adds three entries. I create the list with these three
entries. However, when I move to the notebook tab where the list is
displayed, only one entry displays. When I sit still, after ~2 seconds the
second entry appears. After another 2 seconds, the third entry is there.
At that point I can work with the list as usual (click around, etcetera).

Either I'm daft, or this particular instance of my pluggable list is
behaving in an extremely peculiar way ;). It doesn't have anything to do
with the p2p code as far as I can see - when I open the list, the three
search results are in and I feed the list with a copy (so even if the list
would trigger events and the list control would react to it, that's not
happening).

I'm going to make dinner. Maybe that'll help :P
Loading...