Does anybody know a safe rule of thumb for building up a consistent color scheme using SymbolicPaint? It seems that even the slightest modifications to the methods of LookPolicy>>installPlatformPreferencesFrom:on: (in subclasses) cause infinite recursion upon color lookup, which effectively hangs the VM. Where's the best place to trap this recursion? (and possibly break it up by answering a default value). Unfortunately this is extremely hard to debug, because the debugger window will - of course - also access the paint hierarchy. After hours of digging, it's getting frustrating. Any hint is appreciated. Andre |
Don't know if this will help. I added the following to our system quite
awhile ago to detect an infinite recursion. Instead of the halt:, you could install a default paint. HierarchicalSymbolicPaint installOn: aGraphicsContext | foundPaint | self needsFixingMethod. foundPaint := aGraphicsContext paintPreferencesMatchAt: self. foundPaint = self ifTrue: [self halt: 'infinite loop installing paint']. ^(foundPaint) installOn: aGraphicsContext "detect infinite loop. we have not seen this problem in awhile. the last case occured bringing up an image on linux that was last saved on windows" -----Original Message----- From: [hidden email] [mailto:[hidden email]] Sent: Friday, February 23, 2007 9:18 AM To: vwnc-list Subject: [VW7.4.1] SymbolicPaint hangs VM with infinite recursion Does anybody know a safe rule of thumb for building up a consistent color scheme using SymbolicPaint? It seems that even the slightest modifications to the methods of LookPolicy>>installPlatformPreferencesFrom:on: (in subclasses) cause infinite recursion upon color lookup, which effectively hangs the VM. Where's the best place to trap this recursion? (and possibly break it up by answering a default value). Unfortunately this is extremely hard to debug, because the debugger window will - of course - also access the paint hierarchy. After hours of digging, it's getting frustrating. Any hint is appreciated. Andre |
[hidden email] wrote: > Don't know if this will help. I added the following to our system quite > awhile ago to detect an infinite recursion. Instead of the halt:, you > could install a default paint. > Thank you. This led me to a more detailed examination of the matter. I understood that the hierarchy itself is static, i.e. initialized only once. So checking the hierarchy at runtime doesn't make sense. Where the actual recursion happens is with the assignments made in a ColorPreferences dictionary dynamically. Problems only occur when one SymbolicPaint is associated with another SymbolicPaint that's already in its parent chain. I've seen this when look policies decide to "customize" the LookPreferences of widgets on the fly. This is especially the case with the WindowsXP look that "patches" background colors during widget creation. Basically, I discovered assignments of the form (example) aColorPreferences matchAt: SymbolicPaint background put: SymbolicPaint buttonBackground The above message will create an infinite recursion, if there's no physical Paint assigned to 'buttonBackground' yet, which would terminate the recursive lookup. A simple solution would be to detect these illegal assignments before they are made. I wrote the following code that effectively eliminates the problem: Paint>>hasParent: aPaint "Physical paint is not in a hierarchy" ^false HierarchicalSymbolicPaint>>hasParent: aPaint "Answer true, if the argument is in the parent chain of the receiver" ^parent = aPaint or:[ parent hasParent: aPaint ] Paint>>isLegalValueFor: aSymbolicPaint "Answer true, if the receiver may be mapped to the argument in a ChainedColorPreferences" ^true SymbolicPaint>>isLegalValueFor: aSymbolicPaint "Answer true, if the receiver may be mapped to the argument in a ChainedColorPreferences" ^self ~= aSymbolicPaint and:[ (self hasParent: aSymbolicPaint) not ] ChainedColorPreferences>>matchAt: aSymbolicPaint put: value "### OVERRIDE: Check if we are about to create an infinite cycle:" (value isLegalValueFor: aSymbolicPaint) ifFalse:[ (self exactMatchAt: value ifAbsent: nil) isNil ifTrue:[ ^aSymbolicPaint hierarchyCorruptedError: value ]]. node == nil ifTrue: [node := self allocateNode]. node matchAt: aSymbolicPaint put: value. ^value SymbolicPaint>>hierarchyCorruptedError: aPaint "Issue a warning and answer a default paint" Transcript cr; show: ( 'ERROR: matchAt: <1s> put: <2s> is illegal' expandMacrosWith: self printString with: aPaint printString ). ^self class foreground I haven't tested if the additional guard code affects performance in any way, but it works like a charm. I would suggest using this utility in a development environment only, or if actual problems occured. Andre |
Free forum by Nabble | Edit this page |