resizing deep window hierarchy

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

resizing deep window hierarchy

Möbus. Manfred

We found some of our screens did not resize properly when run under win7/64bit.

This seems to be a general problem of windows, and is described in http://blogs.msdn.com/b/alejacma/archive/2008/11/20/controls-won-t-get-resized-once-the-nesting-hierarchy-of-windows-exceeds-a-certain-depth-x64.aspx. Would never have guessed MS to introduce such a silly limitation that something important like a kernel stack can so easily be exhausted, when “64bit” seems to bring soo much memory and address space.

 

The solution proposed in the article (using asynchronous BeginInvoke .net function) might translate into VSE Notifier>>postInputEvent:, but I found it too uncertain when the deferred code will be executed given the one-thread nature of our environment.

 

So my solution was to move resizing of children from inside wmSize:with: recursive processing to the caller; this means resizing a hierarchy of controls is still done off the smalltalk stack, but this apparently is much larger than the kernel stack.

 

The following methods (changes in red) are a quick fix to the problem. Examining the rest of the code will probably reveal other resizing scenarios (such as the #resize:deferInfo: stuff) and make more changes appropriate, but after all it is probably not worthwhile to avoid every and all recursive wm message call, since the kernel stack isn’t exactly zero. Also one might use something like [   ] ensure: [ ].

 

Manfred.

 

 

 

!Window methodsFor: #(Private) !

 

resizeWindow

    "(Private) Private - Change the size of the window

         for the receiver."

 

    | ref |

 

    ref := nil asValueReference.

    self stopPropagateSizeChanged: ref.

    self handle setWindowPos: nil

        rectangle: rectangle

        fs: SwpNozorder.

    self stopPropagateSizeChanged: nil.

    rectangle := 0 @ 0 extent: self extent.

    ref value = true ifTrue: [

        self sizeChanged: self extent ].  ! !

 

 

!Window methodsFor: #(Private) !

 

stopPropagateSizeChanged: aValueReference

    "(Private) store an object where to record that

wmSize:with: has been called"

 

    self propertyAt: #stopPropagateSizeChanged put: aValueReference  ! !

 

 

!Window methodsFor: #(Private) !

 

checkPropagateSizeChanged

    "(Private) invoked during wm_size. when someone has set up a handler and will call

   sizeChanged: later, record this window as interested in this method.

    return false in this case (i.e. caller must not invoke sizeChanged: now),

    return true when no none has set up a handler and sizeChanged: must be propagated now"

 

    | deferredList flagRef |

 

    (flagRef := self propertyAt: #stopPropagateSizeChanged) isNil

        ifTrue: [ ^false ]

        ifFalse: [

            flagRef value: true.

            ^true ].  ! !

 

 

!Window methodsFor: #(Private) !

 

wmSize: wordInteger with: longInteger

    "(Private) Private - Process the window resizing message."

 

    | extent |

    extent := ( WinPoint fromInteger: longInteger ) asPoint.

    ( extent x = 0 or: [ extent y = 0 ] )

        ifFalse: [

            self checkPropagateSizeChanged ifFalse: [

                self sizeChanged: extent ].].

    ^nil! !

 

 

 



Treffen Sie AEB vom 13.-15. März 2012 auf der LogiMAT in Stuttgart. Halle 7, Stand 261.
Vereinbaren Sie jetzt einen Termin und erhalten eine Eintrittskarte: www.aeb.de/logimat
*** this signature added by listserv *** *** Visit http://www.listserv.dfn.de/archives/vswe-l.html *** *** for archive browsing and VSWE-L membership management ***
Reply | Threaded
Open this post in threaded view
|

Re: resizing deep window hierarchy

Todor Todorov

Hey Manfred,

 

Your solution works, but you should be careful about few things. The WM_SIZE… messages afaik gives you the client area, which in turn is used to calc the area of the children. That means that if you resize by hand (the way you do it), before doing recursive resizing, you will need to calculate what the client area of the window will be given a certain total area.

 

I can’t remember if there are helper functions for this in Windows. If not, you will have to take into account the different type of borders and whatever Window may consider non-client.

 

If I were you, I would do a hybrid solution.

1.    Do the way you do it, by manually setting the size.

2.    Have similar test as you have, but check the real size you get in WM_SIZE with the one you’ve calc’ed. If they match, then your by-hand resizing worked.

3.    Still have the input-event mechanism, just in case you miscalculated the sizes.

4.    Remember that in intensive resizing, the queue may not be emptied immediately, so remove duplicates.

 

And yes, the input event is the same as the BeginInvoke in .Net is the same as the CurrentEvents queue (#sendInputEvent: and #postInpitEvent:). They both add an event to a queue to be processed by the UI thread when it’s idle.

 

-- Todor

 

 

 

From: Using Visual Smalltalk for Windows/Enterprise [mailto:[hidden email]] On Behalf Of Möbus. Manfred
Sent: 13. februar 2012 11:05
To: [hidden email]
Subject: resizing deep window hierarchy

 

We found some of our screens did not resize properly when run under win7/64bit.

This seems to be a general problem of windows, and is described in http://blogs.msdn.com/b/alejacma/archive/2008/11/20/controls-won-t-get-resized-once-the-nesting-hierarchy-of-windows-exceeds-a-certain-depth-x64.aspx. Would never have guessed MS to introduce such a silly limitation that something important like a kernel stack can so easily be exhausted, when “64bit” seems to bring soo much memory and address space.

 

The solution proposed in the article (using asynchronous BeginInvoke .net function) might translate into VSE Notifier>>postInputEvent:, but I found it too uncertain when the deferred code will be executed given the one-thread nature of our environment.

 

So my solution was to move resizing of children from inside wmSize:with: recursive processing to the caller; this means resizing a hierarchy of controls is still done off the smalltalk stack, but this apparently is much larger than the kernel stack.

 

The following methods (changes in red) are a quick fix to the problem. Examining the rest of the code will probably reveal other resizing scenarios (such as the #resize:deferInfo: stuff) and make more changes appropriate, but after all it is probably not worthwhile to avoid every and all recursive wm message call, since the kernel stack isn’t exactly zero. Also one might use something like [   ] ensure: [ ].

 

Manfred.

 

 

 

!Window methodsFor: #(Private) !

 

resizeWindow

    "(Private) Private - Change the size of the window

         for the receiver."

 

    | ref |

 

    ref := nil asValueReference.

    self stopPropagateSizeChanged: ref.

    self handle setWindowPos: nil

        rectangle: rectangle

        fs: SwpNozorder.

    self stopPropagateSizeChanged: nil.

    rectangle := 0 @ 0 extent: self extent.

    ref value = true ifTrue: [

        self sizeChanged: self extent ].  ! !

 

 

!Window methodsFor: #(Private) !

 

stopPropagateSizeChanged: aValueReference

    "(Private) store an object where to record that

wmSize:with: has been called"

 

    self propertyAt: #stopPropagateSizeChanged put: aValueReference  ! !

 

 

!Window methodsFor: #(Private) !

 

checkPropagateSizeChanged

    "(Private) invoked during wm_size. when someone has set up a handler and will call

   sizeChanged: later, record this window as interested in this method.

    return false in this case (i.e. caller must not invoke sizeChanged: now),

    return true when no none has set up a handler and sizeChanged: must be propagated now"

 

    | deferredList flagRef |

 

    (flagRef := self propertyAt: #stopPropagateSizeChanged) isNil

        ifTrue: [ ^false ]

        ifFalse: [

            flagRef value: true.

            ^true ].  ! !

 

 

!Window methodsFor: #(Private) !

 

wmSize: wordInteger with: longInteger

    "(Private) Private - Process the window resizing message."

 

    | extent |

    extent := ( WinPoint fromInteger: longInteger ) asPoint.

    ( extent x = 0 or: [ extent y = 0 ] )

        ifFalse: [

            self checkPropagateSizeChanged ifFalse: [

                self sizeChanged: extent ].].

    ^nil! !

 

 

 



Treffen Sie AEB vom 13.-15. März 2012 auf der LogiMAT in Stuttgart. Halle 7, Stand 261.
Vereinbaren Sie jetzt einen Termin und erhalten eine Eintrittskarte: www.aeb.de/logimat

*** this signature added by listserv *** *** Visit http://www.listserv.dfn.de/archives/vswe-l.html *** *** for archive browsing and VSWE-L membership management ***

*** this signature added by listserv *** *** Visit http://www.listserv.dfn.de/archives/vswe-l.html *** *** for archive browsing and VSWE-L membership management ***