Intro to Microsoft COM for Smalltalkers

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

Re: Intro to Microsoft COM for Smalltalkers

philippeback
Cool.

Now, I think we should do: 

WorldState MinCycleLapse: 16.

So that we get a real 60FPS when moving windows around instead of the default 20 which is 50FPS, and not as smooth.

Set it at 10 and it is too much, but hey, we have a lot of power these days.

Try to set it to 200 and suffer :-p


Phil



On Mon, Oct 3, 2016 at 8:18 PM, CodeDmitry <[hidden email]> wrote:
You seem to have answered my question as I was revising it D:



--
View this message in context: http://forum.world.st/Intro-to-Microsoft-COM-for-Smalltalkers-tp4917738p4917916.html
Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.



Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

stepharo
In reply to this post by philippeback



Le 3/10/16 à 17:25, [hidden email] a écrit :
Case in point, I am submitting a proposal here: https://devfest.be/blog/posts/cfp/

That's Google tech event here.

I proposed to showcase MDL in Pharo along with workshop. Let's see how it goes...

Nice :)
Cyril will be happy :)

Stef

Phil

On Mon, Oct 3, 2016 at 4:43 PM, Offray Vladimir Luna Cárdenas <[hidden email]> wrote:
Hi,


On 02/10/16 17:13, [hidden email] wrote:

[...]
Use it whenever you can, it will force you to understand how to do real stuff with it properly.

I do hackathons with it. https://hackernoon.com/hackapost-how-hackathons-can-be-the-best-learning-tool-under-the-sun-9c97e567e0a5


As complementary to the infrastructure, code standards,  libraries and so on, a needed contribution, from the social dynamics perspective, are hachathons and workshops. We're making them regularly here (link at [1], in Spanish), with a critical data/code literacy approach. Last week we have our 5th edition and this week we're going to make an agile 6th edition.

[1] http://mutabit.com/dataweek/

I found the Pharo community very open to contribution. The fast feedback loop [2] is experienced here in a very visible way and most of the time the community is welcoming (with notable few exceptions, "ad hominen" attacks and poor argumentation, but also with a good self-correcting feedback from the broader community).

[2] http://www.slideshare.net/MarcusDenker/perfection-feedback-loops-or-why-worse-is-better-65540840

So is not a perfect place, as any other, but you'll find a way of contributing that is considered worthy and encouraged and even supported with economical resources from Pharo Association / Consorcium from time to time.

Welcome here, you and your contribution ;-),

Offray




Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

stepharo
In reply to this post by Ben Coman
Thanks Ben.

I can tell you that we want to remove all such activeHand. :)

One day it will come.

Stef


Le 3/10/16 à 12:25, Ben Coman a écrit :

> On Mon, Oct 3, 2016 at 6:08 PM, Ben Coman <[hidden email]> wrote:
>> On Mon, Oct 3, 2016 at 3:49 PM, CodeDmitry <[hidden email]> wrote:
>>> a JavaScript timeout is a function that takes a block and a period of time,
>>> and after  this period of time, puts the block at the end of the event
>>> queue, to be executed as soon as the runtime is done performing the tasks in
>>> front of it.
>>>
>>> I am not sure if Pharo has an event queue, so it's a bit harder to do
>>> it(since without one you can't ensure only one thing happens at a time, and
>>> strange things can happen).
>>>
>>> That said, in simplest terms, imagine writing a clock app for Pharo, which
>>> updates time every second, in JS this would be done by setting an interval
>>> that ticks every 1000ms, and each time places the callback function(block)
>>> at the end of the event queue.
>>>
>>> Related: https://www.youtube.com/watch?time_continue=1&v=8aGhZQkoFbQ
>> Pharo has a single threaded VM, but multiple green threads can run concurrently.
>> The closest to the event loop you are thinking of most likely the
>> Morphic UI Process
>> which you can see using World > Tools > Process Browser.  When you execute code
>> from Playground it runs in that Process (note what Smalltalk
>> historically (circa 1970s?) has
>> called a Process is today more commonly know as a Green Thread)
>>
>> If you select Morphic UI Process  you will see its call stack on the
>> right, where an interesting method is WorldState>>doOneCycleFor:
>> You can gain some insight by turning on auto-update in the Process
>> Browser, then open a Browser on WorldState>>doOneCycleFor:
>> and put "self haltOnce" at the top, then enable it via...
>> Pharo 5: World > System > Enable halt/inspect once.
>> Pharo 6: World > Debugging > Enable all break/inspect once.
>>
>> You will see in the Process Browser that a new Morphic UI Process is
>> spawned, and the original Morphic UI Process call stack now has
>> #debugProcess at the top
>> and a debug window appears that you can step through.  Note, since two
>> UI loops are executing here, the image may lock up, but usually its
>> fine so hey! live on the edge!
>
> I meant to ask the list about a bug I hit doing this....
>
> Putting a "self haltOnce" here...
>
>    WorldState>>doOneCycleNowFor: aWorld
>      DisplayScreen checkForNewScreenSize.
>      self haltOnce.
>      "process user input events"
>      LastCycleTime := Time millisecondClockValue.
>      self handsDo: [:h |
>          self activeHand: h.
>          h processEvents.
>          self activeHand: nil.
>      ].
>      self activeHand: self hands first.
>      aWorld runStepMethods. "there are currently some variations here"
>      self displayWorldSafely: aWorld.
>
>
> When stepping over "self activeHand: nil."
> another debugger appears MNU: receiver of "releaseKeyboardFocus:" is nil
> in GLMPagerPanePreviewMorph(Morph)>>delete
>
>    self activeHand
>       releaseKeyboardFocus: self;
>       releaseMouseFocus: self.
>
>
> This can obviously be fixed by wrapping "self activeHand" with an #ifNil:
> but alternatively I wonder if the "self activeHand: nil" is really needed?
> It seems redundant since activeHand is set at the top of the loop and
> immediately after exiting the loop.
> Eliminating it would reduce the propagation of #ifNil: anti-pattern.
>
> https://pharo.fogbugz.com/default.asp?19169
>
> cheers -ben
>
>> In #runStepMethodsIn: you'll see "queue := self class
>> deferredUIMessages" for which you enqueue items like this...
>> http://forum.world.st/Issue-3562-in-pharo-Deferred-UI-messages-executed-slowly-td3228060.html
>>
>> After processing the deferred UI messages, each Morph's #step method
>> is processed by #runLocalStepMethodsIn:
>> refer... http://wiki.squeak.org/squeak/2096
>>
>> The display is then rendered by #displayWorldSafely: calling...
>> --> #displayWorld
>> --> #displayWorld:submorphs:
>> which then is a lot to trace through, but depending on the graphics
>> back end eventually ends up calling...
>> Canvas>>fullDrawMorph:    which ultimately invokes one of many #drawOn:
>> or...
>> AthensCanvas>>fullDrawMorph:    which ultimately invokes one of many
>> #drawOnAthensCanvas:
>>
>>
>> So, for a regular timed UI animation, you would define your custom
>> morph's #step and #stepTime methods,
>> and for lower level stuff you would fork like Dennis suggests.
>>
>> cheers -ben
>


Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

stepharo
In reply to this post by philippeback
ere is some interesting event loop stuff from Tcl.


I wish we had some easy Tk UI building things in Pharo.

Me too :)
First I want Bloc to get out and be ready for integration to Pharo but it takes time.


Spec is okay but not intuitive. As it is the only thing that exposes the myriad of various Morphs we have and shields us (somewhat) from the underlying details, we have to use it, but its explorability is really detrimental to the livecoding side of Pharo.

Spec is not to build fun morphic things :)


Phil

On Mon, Oct 3, 2016 at 12:25 PM, Ben Coman <[hidden email]> wrote:
On Mon, Oct 3, 2016 at 6:08 PM, Ben Coman <[hidden email]> wrote:
> On Mon, Oct 3, 2016 at 3:49 PM, CodeDmitry <[hidden email]> wrote:
>> a JavaScript timeout is a function that takes a block and a period of time,
>> and after  this period of time, puts the block at the end of the event
>> queue, to be executed as soon as the runtime is done performing the tasks in
>> front of it.
>>
>> I am not sure if Pharo has an event queue, so it's a bit harder to do
>> it(since without one you can't ensure only one thing happens at a time, and
>> strange things can happen).
>>
>> That said, in simplest terms, imagine writing a clock app for Pharo, which
>> updates time every second, in JS this would be done by setting an interval
>> that ticks every 1000ms, and each time places the callback function(block)
>> at the end of the event queue.
>>
>> Related: https://www.youtube.com/watch?time_continue=1&v=8aGhZQkoFbQ
>
> Pharo has a single threaded VM, but multiple green threads can run concurrently.
> The closest to the event loop you are thinking of most likely the
> Morphic UI Process
> which you can see using World > Tools > Process Browser.  When you execute code
> from Playground it runs in that Process (note what Smalltalk
> historically (circa 1970s?) has
> called a Process is today more commonly know as a Green Thread)
>
> If you select Morphic UI Process  you will see its call stack on the
> right, where an interesting method is WorldState>>doOneCycleFor:
> You can gain some insight by turning on auto-update in the Process
> Browser, then open a Browser on WorldState>>doOneCycleFor:
> and put "self haltOnce" at the top, then enable it via...
> Pharo 5: World > System > Enable halt/inspect once.
> Pharo 6: World > Debugging > Enable all break/inspect once.
>
> You will see in the Process Browser that a new Morphic UI Process is
> spawned, and the original Morphic UI Process call stack now has
> #debugProcess at the top
> and a debug window appears that you can step through.  Note, since two
> UI loops are executing here, the image may lock up, but usually its
> fine so hey! live on the edge!


I meant to ask the list about a bug I hit doing this....

Putting a "self haltOnce" here...

  WorldState>>doOneCycleNowFor: aWorld
    DisplayScreen checkForNewScreenSize.
    self haltOnce.
    "process user input events"
    LastCycleTime := Time millisecondClockValue.
    self handsDo: [:h |
        self activeHand: h.
        h processEvents.
        self activeHand: nil.
    ].
    self activeHand: self hands first.
    aWorld runStepMethods. "there are currently some variations here"
    self displayWorldSafely: aWorld.


When stepping over "self activeHand: nil."
another debugger appears MNU: receiver of "releaseKeyboardFocus:" is nil
in GLMPagerPanePreviewMorph(Morph)>>delete

  self activeHand
     releaseKeyboardFocus: self;
     releaseMouseFocus: self.


This can obviously be fixed by wrapping "self activeHand" with an #ifNil:
but alternatively I wonder if the "self activeHand: nil" is really needed?
It seems redundant since activeHand is set at the top of the loop and
immediately after exiting the loop.
Eliminating it would reduce the propagation of #ifNil: anti-pattern.

https://pharo.fogbugz.com/default.asp?19169

cheers -ben

>
> In #runStepMethodsIn: you'll see "queue := self class
> deferredUIMessages" for which you enqueue items like this...
> http://forum.world.st/Issue-3562-in-pharo-Deferred-UI-messages-executed-slowly-td3228060.html
>
> After processing the deferred UI messages, each Morph's #step method
> is processed by #runLocalStepMethodsIn:
> refer... http://wiki.squeak.org/squeak/2096
>
> The display is then rendered by #displayWorldSafely: calling...
> --> #displayWorld
> --> #displayWorld:submorphs:
> which then is a lot to trace through, but depending on the graphics
> back end eventually ends up calling...
> Canvas>>fullDrawMorph:    which ultimately invokes one of many #drawOn:
> or...
> AthensCanvas>>fullDrawMorph:    which ultimately invokes one of many
> #drawOnAthensCanvas:
>
>
> So, for a regular timed UI animation, you would define your custom
> morph's #step and #stepTime methods,
> and for lower level stuff you would fork like Dennis suggests.
>
> cheers -ben




Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

Thibault Raffaillac
In reply to this post by CodeDmitry
Thanks for these mails, that's actually very helpful!
I am working on a shorter syntax for animations at the moment (than GLMAnimation, Viva, Bloc-Animation), and could not find a proper equivalent to requestAnimationFrame (i.e. that would be independent of any UI yet in sync with display, and as simple as possible).
My solution was to repeatedly register to deferredUIMessages, implementing an intermediate block to add a timestamp like requestAnimationFrame (works wonders http://smalltalkhub.com/#!/~ThibaultRaffaillac/Animation)

Cheers,
Thibault

ps: I'll ask Guille asap for the state of ReactiveExtensions (lacks comments)

> Also, check
>
> MorphicUIManager>>#spawnNewProcess
>
> UIProcess := [
> [World doOneCycle.  Processor yield.  false] whileFalse: [].
> ] newProcess priority: Processor userSchedulingPriority.
> UIProcess name: 'Morphic UI Process'.
> UIProcess resume
>
> digging into doOneCycle, you'll find:
>
> #doOneCycleFor: aWorld
> "Do one cycle of the interaction loop. This method is called *repeatedly
> *when
> the world is running. This is a moderately private method; a better
> alternative is usually either to wait for events or to check the state of
> things from #step methods."
>
> self interCyclePause: MinCycleLapse.
> self doOneCycleNowFor: aWorld.
>
>
> The interCyclePause is what make the UI timing alignment proper (notice
> serverMode) [and some Squeak remnant mention]:
>
> interCyclePause: milliSecs
> "delay enough that the previous cycle plus the amount of delay will equal
> milliSecs.  If the cycle is already expensive, then no delay occurs.
> However, if the system is idly waiting for interaction from the user, the
> method will delay for a proportionally long time and cause the overall CPU
> usage of *Squeak* to be low.
> If self serverMode returns true then, always do a complete delay of 50ms,
> independant of my argument. This prevents the freezing problem described in
> Mantis #6581"
>
> | wait wait2 |
>         "*a very long assignment*"
> wait := self serverMode
>     ifTrue: [ 50 ]
>     ifFalse:
> [ wait2 := (lastCycleTime notNil and: [CanSurrenderToOS ~~ false])
>         ifFalse: [ 0 ]
>         ifTrue: [ lastCycleTime + milliSecs - Time millisecondClockValue ].
>
>       self flag: 'Issue 14754 - wait2>millisecs is only True for clock
> rollover. Remove it once DelayScheduler based on microsecondClock - Ben
> Coman 19.01.2015'.  "*<---- maybe we want this #flag: not to be called all
> the time* "
>       wait2 > milliSecs
>         ifTrue: [ 0 ]
>         ifFalse: [ wait2 ].
> ].
> wait > 0 ifTrue: [ (Delay forMilliseconds: wait) wait ].   "<------- wait
> is not #>>wait"
>
> lastCycleTime := Time millisecondClockValue.
> CanSurrenderToOS := true.
>
> Now, yeah, how do get stuff to be painted on the  screen?
>
> Like this:
>
> displayWorld: aWorld submorphs: submorphs
> "Update this world's display."
>
> | deferredUpdateMode handsToDraw allDamage |
>
> submorphs do: [:m | m fullBounds].  "force re-layout if needed"
> self checkIfUpdateNeeded ifFalse: [^ self].  "display is already up-to-date"
>
> deferredUpdateMode := self doDeferredUpdatingFor: aWorld.
> deferredUpdateMode ifFalse: [self assuredCanvas].
> canvas roundCornersOf: aWorld during:[ | worldDamageRects handDamageRects |
> worldDamageRects := self drawWorld: aWorld submorphs: submorphs
> invalidAreasOn: canvas.  "repair world's damage on canvas"
> "self handsDo:[:h| h noticeDamageRects: worldDamageRects]."
> handsToDraw := self selectHandsToDrawForDamage: worldDamageRects.
> handDamageRects := handsToDraw collect: [:h | h savePatchFrom: canvas].
> allDamage := worldDamageRects, handDamageRects.
>
> handsToDraw reverseDo: [:h | canvas fullDrawMorph: h].  "draw hands onto
> world canvas"
> ].
> "*make this true to flash damaged areas for testing*"
> self class debugShowDamage ifTrue: [aWorld flashRects: allDamage color:
> Color black].
>
> canvas finish.
> "quickly copy altered rects of canvas to Display:"
> deferredUpdateMode
> ifTrue: [self forceDamageToScreen: allDamage]
> ifFalse: [canvas showAt: aWorld viewBox origin invalidRects: allDamage].
> handsToDraw do: [:h | h restoreSavedPatchOn: canvas].  "restore world
> canvas under hands"
> Display deferUpdates: false; forceDisplayUpdate.
>
> The VM will take care of throwing the bits to the display in various ways.
> Interesting to look how it is done for Windows, OSX, and Linux.
>
> So you have about a full view now.
>
> Timing wise, there is also some interaction with the VM occuring elsewhere.
> Pharo is still polling deep inside.  epoll etc isn't there yet, hence the
> little idle CPU usage when doing nothing.
>
> Good luck doing this UI trip with other platforms, not to mention change or
> instrument it the way you like.
>
> Pharo is really cool for this as it helps in learning about a lot of things.
>
> Want to do sockets?
> Do the high level stuff in Pharo and dig in the VM to see how it is done
> down under for a set of platforms.
>
> Enjoy.
>
> Phil

Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

Ben Coman
On Fri, Oct 7, 2016 at 9:14 PM, Thibault Raffaillac
<[hidden email]> wrote:

> Thanks for these mails, that's actually very helpful!
> I am working on a shorter syntax for animations at the moment (than GLMAnimation, Viva, Bloc-Animation), and could not find a proper equivalent to requestAnimationFrame (i.e. that would be independent of any UI yet in sync with display, and as simple as possible).
> My solution was to repeatedly register to deferredUIMessages, implementing an intermediate block to add a timestamp like requestAnimationFrame (works wonders http://smalltalkhub.com/#!/~ThibaultRaffaillac/Animation)
>
> Cheers,
> Thibault
>
> ps: I'll ask Guille asap for the state of ReactiveExtensions (lacks comments)
>
>> Also, check
>>
>> MorphicUIManager>>#spawnNewProcess
>>
>> UIProcess := [
>> [World doOneCycle.  Processor yield.  false] whileFalse: [].
>> ] newProcess priority: Processor userSchedulingPriority.
>> UIProcess name: 'Morphic UI Process'.
>> UIProcess resume
>>
>> digging into doOneCycle, you'll find:
>>
>> #doOneCycleFor: aWorld
>> "Do one cycle of the interaction loop. This method is called *repeatedly
>> *when
>> the world is running. This is a moderately private method; a better
>> alternative is usually either to wait for events or to check the state of
>> things from #step methods."
>>
>> self interCyclePause: MinCycleLapse.
>> self doOneCycleNowFor: aWorld.
>>
>>
>> The interCyclePause is what make the UI timing alignment proper (notice
>> serverMode) [and some Squeak remnant mention]:
>>
>> interCyclePause: milliSecs
>> "delay enough that the previous cycle plus the amount of delay will equal
>> milliSecs.  If the cycle is already expensive, then no delay occurs.
>> However, if the system is idly waiting for interaction from the user, the
>> method will delay for a proportionally long time and cause the overall CPU
>> usage of *Squeak* to be low.
>> If self serverMode returns true then, always do a complete delay of 50ms,
>> independant of my argument. This prevents the freezing problem described in
>> Mantis #6581"
>>
>> | wait wait2 |
>>         "*a very long assignment*"
>> wait := self serverMode
>>     ifTrue: [ 50 ]
>>     ifFalse:
>> [ wait2 := (lastCycleTime notNil and: [CanSurrenderToOS ~~ false])
>>         ifFalse: [ 0 ]
>>         ifTrue: [ lastCycleTime + milliSecs - Time millisecondClockValue ].
>>
>>       self flag: 'Issue 14754 - wait2>millisecs is only True for clock
>> rollover. Remove it once DelayScheduler based on microsecondClock - Ben
>> Coman 19.01.2015'.  "*<---- maybe we want this #flag: not to be called all

Yes, good idea. I'll see to it.
cheers -ben

Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

stepharo
In reply to this post by Thibault Raffaillac
Thibault

you should talk also with Glenn and Alain to get feedback. They will
visit us in Nov.


Stef


Le 7/10/16 à 15:14, Thibault Raffaillac a écrit :

> Thanks for these mails, that's actually very helpful!
> I am working on a shorter syntax for animations at the moment (than GLMAnimation, Viva, Bloc-Animation), and could not find a proper equivalent to requestAnimationFrame (i.e. that would be independent of any UI yet in sync with display, and as simple as possible).
> My solution was to repeatedly register to deferredUIMessages, implementing an intermediate block to add a timestamp like requestAnimationFrame (works wonders http://smalltalkhub.com/#!/~ThibaultRaffaillac/Animation)
>
> Cheers,
> Thibault
>
> ps: I'll ask Guille asap for the state of ReactiveExtensions (lacks comments)
>
>> Also, check
>>
>> MorphicUIManager>>#spawnNewProcess
>>
>> UIProcess := [
>> [World doOneCycle.  Processor yield.  false] whileFalse: [].
>> ] newProcess priority: Processor userSchedulingPriority.
>> UIProcess name: 'Morphic UI Process'.
>> UIProcess resume
>>
>> digging into doOneCycle, you'll find:
>>
>> #doOneCycleFor: aWorld
>> "Do one cycle of the interaction loop. This method is called *repeatedly
>> *when
>> the world is running. This is a moderately private method; a better
>> alternative is usually either to wait for events or to check the state of
>> things from #step methods."
>>
>> self interCyclePause: MinCycleLapse.
>> self doOneCycleNowFor: aWorld.
>>
>>
>> The interCyclePause is what make the UI timing alignment proper (notice
>> serverMode) [and some Squeak remnant mention]:
>>
>> interCyclePause: milliSecs
>> "delay enough that the previous cycle plus the amount of delay will equal
>> milliSecs.  If the cycle is already expensive, then no delay occurs.
>> However, if the system is idly waiting for interaction from the user, the
>> method will delay for a proportionally long time and cause the overall CPU
>> usage of *Squeak* to be low.
>> If self serverMode returns true then, always do a complete delay of 50ms,
>> independant of my argument. This prevents the freezing problem described in
>> Mantis #6581"
>>
>> | wait wait2 |
>>          "*a very long assignment*"
>> wait := self serverMode
>>      ifTrue: [ 50 ]
>>      ifFalse:
>> [ wait2 := (lastCycleTime notNil and: [CanSurrenderToOS ~~ false])
>>          ifFalse: [ 0 ]
>>          ifTrue: [ lastCycleTime + milliSecs - Time millisecondClockValue ].
>>
>>        self flag: 'Issue 14754 - wait2>millisecs is only True for clock
>> rollover. Remove it once DelayScheduler based on microsecondClock - Ben
>> Coman 19.01.2015'.  "*<---- maybe we want this #flag: not to be called all
>> the time* "
>>        wait2 > milliSecs
>>          ifTrue: [ 0 ]
>>          ifFalse: [ wait2 ].
>> ].
>> wait > 0 ifTrue: [ (Delay forMilliseconds: wait) wait ].   "<------- wait
>> is not #>>wait"
>>
>> lastCycleTime := Time millisecondClockValue.
>> CanSurrenderToOS := true.
>>
>> Now, yeah, how do get stuff to be painted on the  screen?
>>
>> Like this:
>>
>> displayWorld: aWorld submorphs: submorphs
>> "Update this world's display."
>>
>> | deferredUpdateMode handsToDraw allDamage |
>>
>> submorphs do: [:m | m fullBounds].  "force re-layout if needed"
>> self checkIfUpdateNeeded ifFalse: [^ self].  "display is already up-to-date"
>>
>> deferredUpdateMode := self doDeferredUpdatingFor: aWorld.
>> deferredUpdateMode ifFalse: [self assuredCanvas].
>> canvas roundCornersOf: aWorld during:[ | worldDamageRects handDamageRects |
>> worldDamageRects := self drawWorld: aWorld submorphs: submorphs
>> invalidAreasOn: canvas.  "repair world's damage on canvas"
>> "self handsDo:[:h| h noticeDamageRects: worldDamageRects]."
>> handsToDraw := self selectHandsToDrawForDamage: worldDamageRects.
>> handDamageRects := handsToDraw collect: [:h | h savePatchFrom: canvas].
>> allDamage := worldDamageRects, handDamageRects.
>>
>> handsToDraw reverseDo: [:h | canvas fullDrawMorph: h].  "draw hands onto
>> world canvas"
>> ].
>> "*make this true to flash damaged areas for testing*"
>> self class debugShowDamage ifTrue: [aWorld flashRects: allDamage color:
>> Color black].
>>
>> canvas finish.
>> "quickly copy altered rects of canvas to Display:"
>> deferredUpdateMode
>> ifTrue: [self forceDamageToScreen: allDamage]
>> ifFalse: [canvas showAt: aWorld viewBox origin invalidRects: allDamage].
>> handsToDraw do: [:h | h restoreSavedPatchOn: canvas].  "restore world
>> canvas under hands"
>> Display deferUpdates: false; forceDisplayUpdate.
>>
>> The VM will take care of throwing the bits to the display in various ways.
>> Interesting to look how it is done for Windows, OSX, and Linux.
>>
>> So you have about a full view now.
>>
>> Timing wise, there is also some interaction with the VM occuring elsewhere.
>> Pharo is still polling deep inside.  epoll etc isn't there yet, hence the
>> little idle CPU usage when doing nothing.
>>
>> Good luck doing this UI trip with other platforms, not to mention change or
>> instrument it the way you like.
>>
>> Pharo is really cool for this as it helps in learning about a lot of things.
>>
>> Want to do sockets?
>> Do the high level stuff in Pharo and dig in the VM to see how it is done
>> down under for a set of platforms.
>>
>> Enjoy.
>>
>> Phil
>


Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

philippeback
Maybe this could become some kind of pillar file...

But things are changing a lot these days with SDL2 etc.

Any roadmap of these somewhere?

Phil

On Sat, Oct 8, 2016 at 7:03 PM, stepharo <[hidden email]> wrote:
Thibault

you should talk also with Glenn and Alain to get feedback. They will visit us in Nov.


Stef


Le 7/10/16 à 15:14, Thibault Raffaillac a écrit :
Thanks for these mails, that's actually very helpful!
I am working on a shorter syntax for animations at the moment (than GLMAnimation, Viva, Bloc-Animation), and could not find a proper equivalent to requestAnimationFrame (i.e. that would be independent of any UI yet in sync with display, and as simple as possible).
My solution was to repeatedly register to deferredUIMessages, implementing an intermediate block to add a timestamp like requestAnimationFrame (works wonders http://smalltalkhub.com/#!/~ThibaultRaffaillac/Animation)

Cheers,
Thibault

ps: I'll ask Guille asap for the state of ReactiveExtensions (lacks comments)

Also, check

MorphicUIManager>>#spawnNewProcess

UIProcess := [
[World doOneCycle.  Processor yield.  false] whileFalse: [].
] newProcess priority: Processor userSchedulingPriority.
UIProcess name: 'Morphic UI Process'.
UIProcess resume

digging into doOneCycle, you'll find:

#doOneCycleFor: aWorld
"Do one cycle of the interaction loop. This method is called *repeatedly
*when
the world is running. This is a moderately private method; a better
alternative is usually either to wait for events or to check the state of
things from #step methods."

self interCyclePause: MinCycleLapse.
self doOneCycleNowFor: aWorld.


The interCyclePause is what make the UI timing alignment proper (notice
serverMode) [and some Squeak remnant mention]:

interCyclePause: milliSecs
"delay enough that the previous cycle plus the amount of delay will equal
milliSecs.  If the cycle is already expensive, then no delay occurs.
However, if the system is idly waiting for interaction from the user, the
method will delay for a proportionally long time and cause the overall CPU
usage of *Squeak* to be low.
If self serverMode returns true then, always do a complete delay of 50ms,
independant of my argument. This prevents the freezing problem described in
Mantis #6581"

| wait wait2 |
         "*a very long assignment*"
wait := self serverMode
     ifTrue: [ 50 ]
     ifFalse:
[ wait2 := (lastCycleTime notNil and: [CanSurrenderToOS ~~ false])
         ifFalse: [ 0 ]
         ifTrue: [ lastCycleTime + milliSecs - Time millisecondClockValue ].

       self flag: 'Issue 14754 - wait2>millisecs is only True for clock
rollover. Remove it once DelayScheduler based on microsecondClock - Ben
Coman 19.01.2015'.  "*<---- maybe we want this #flag: not to be called all
the time* "
       wait2 > milliSecs
         ifTrue: [ 0 ]
         ifFalse: [ wait2 ].
].
wait > 0 ifTrue: [ (Delay forMilliseconds: wait) wait ].   "<------- wait
is not #>>wait"

lastCycleTime := Time millisecondClockValue.
CanSurrenderToOS := true.

Now, yeah, how do get stuff to be painted on the  screen?

Like this:

displayWorld: aWorld submorphs: submorphs
"Update this world's display."

| deferredUpdateMode handsToDraw allDamage |

submorphs do: [:m | m fullBounds].  "force re-layout if needed"
self checkIfUpdateNeeded ifFalse: [^ self].  "display is already up-to-date"

deferredUpdateMode := self doDeferredUpdatingFor: aWorld.
deferredUpdateMode ifFalse: [self assuredCanvas].
canvas roundCornersOf: aWorld during:[ | worldDamageRects handDamageRects |
worldDamageRects := self drawWorld: aWorld submorphs: submorphs
invalidAreasOn: canvas.  "repair world's damage on canvas"
"self handsDo:[:h| h noticeDamageRects: worldDamageRects]."
handsToDraw := self selectHandsToDrawForDamage: worldDamageRects.
handDamageRects := handsToDraw collect: [:h | h savePatchFrom: canvas].
allDamage := worldDamageRects, handDamageRects.

handsToDraw reverseDo: [:h | canvas fullDrawMorph: h].  "draw hands onto
world canvas"
].
"*make this true to flash damaged areas for testing*"
self class debugShowDamage ifTrue: [aWorld flashRects: allDamage color:
Color black].

canvas finish.
"quickly copy altered rects of canvas to Display:"
deferredUpdateMode
ifTrue: [self forceDamageToScreen: allDamage]
ifFalse: [canvas showAt: aWorld viewBox origin invalidRects: allDamage].
handsToDraw do: [:h | h restoreSavedPatchOn: canvas].  "restore world
canvas under hands"
Display deferUpdates: false; forceDisplayUpdate.

The VM will take care of throwing the bits to the display in various ways.
Interesting to look how it is done for Windows, OSX, and Linux.

So you have about a full view now.

Timing wise, there is also some interaction with the VM occuring elsewhere.
Pharo is still polling deep inside.  epoll etc isn't there yet, hence the
little idle CPU usage when doing nothing.

Good luck doing this UI trip with other platforms, not to mention change or
instrument it the way you like.

Pharo is really cool for this as it helps in learning about a lot of things.

Want to do sockets?
Do the high level stuff in Pharo and dig in the VM to see how it is done
down under for a set of platforms.

Enjoy.

Phil





Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

stepharo

Maybe this could become some kind of pillar file...

But things are changing a lot these days with SDL2 etc.
It is converging
    - SDL2 stabilisation
    - Sparta integrated into Bloc
    - TxText optimisation
    - Bloc stabilization
    Thales guys are starting to use it.

Stef

Any roadmap of these somewhere?

Phil

On Sat, Oct 8, 2016 at 7:03 PM, stepharo <[hidden email]> wrote:
Thibault

you should talk also with Glenn and Alain to get feedback. They will visit us in Nov.


Stef


Le 7/10/16 à 15:14, Thibault Raffaillac a écrit :
Thanks for these mails, that's actually very helpful!
I am working on a shorter syntax for animations at the moment (than GLMAnimation, Viva, Bloc-Animation), and could not find a proper equivalent to requestAnimationFrame (i.e. that would be independent of any UI yet in sync with display, and as simple as possible).
My solution was to repeatedly register to deferredUIMessages, implementing an intermediate block to add a timestamp like requestAnimationFrame (works wonders http://smalltalkhub.com/#!/~ThibaultRaffaillac/Animation)

Cheers,
Thibault

ps: I'll ask Guille asap for the state of ReactiveExtensions (lacks comments)

Also, check

MorphicUIManager>>#spawnNewProcess

UIProcess := [
[World doOneCycle.  Processor yield.  false] whileFalse: [].
] newProcess priority: Processor userSchedulingPriority.
UIProcess name: 'Morphic UI Process'.
UIProcess resume

digging into doOneCycle, you'll find:

#doOneCycleFor: aWorld
"Do one cycle of the interaction loop. This method is called *repeatedly
*when
the world is running. This is a moderately private method; a better
alternative is usually either to wait for events or to check the state of
things from #step methods."

self interCyclePause: MinCycleLapse.
self doOneCycleNowFor: aWorld.


The interCyclePause is what make the UI timing alignment proper (notice
serverMode) [and some Squeak remnant mention]:

interCyclePause: milliSecs
"delay enough that the previous cycle plus the amount of delay will equal
milliSecs.  If the cycle is already expensive, then no delay occurs.
However, if the system is idly waiting for interaction from the user, the
method will delay for a proportionally long time and cause the overall CPU
usage of *Squeak* to be low.
If self serverMode returns true then, always do a complete delay of 50ms,
independant of my argument. This prevents the freezing problem described in
Mantis #6581"

| wait wait2 |
         "*a very long assignment*"
wait := self serverMode
     ifTrue: [ 50 ]
     ifFalse:
[ wait2 := (lastCycleTime notNil and: [CanSurrenderToOS ~~ false])
         ifFalse: [ 0 ]
         ifTrue: [ lastCycleTime + milliSecs - Time millisecondClockValue ].

       self flag: 'Issue 14754 - wait2>millisecs is only True for clock
rollover. Remove it once DelayScheduler based on microsecondClock - Ben
Coman 19.01.2015'.  "*<---- maybe we want this #flag: not to be called all
the time* "
       wait2 > milliSecs
         ifTrue: [ 0 ]
         ifFalse: [ wait2 ].
].
wait > 0 ifTrue: [ (Delay forMilliseconds: wait) wait ].   "<------- wait
is not #>>wait"

lastCycleTime := Time millisecondClockValue.
CanSurrenderToOS := true.

Now, yeah, how do get stuff to be painted on the  screen?

Like this:

displayWorld: aWorld submorphs: submorphs
"Update this world's display."

| deferredUpdateMode handsToDraw allDamage |

submorphs do: [:m | m fullBounds].  "force re-layout if needed"
self checkIfUpdateNeeded ifFalse: [^ self].  "display is already up-to-date"

deferredUpdateMode := self doDeferredUpdatingFor: aWorld.
deferredUpdateMode ifFalse: [self assuredCanvas].
canvas roundCornersOf: aWorld during:[ | worldDamageRects handDamageRects |
worldDamageRects := self drawWorld: aWorld submorphs: submorphs
invalidAreasOn: canvas.  "repair world's damage on canvas"
"self handsDo:[:h| h noticeDamageRects: worldDamageRects]."
handsToDraw := self selectHandsToDrawForDamage: worldDamageRects.
handDamageRects := handsToDraw collect: [:h | h savePatchFrom: canvas].
allDamage := worldDamageRects, handDamageRects.

handsToDraw reverseDo: [:h | canvas fullDrawMorph: h].  "draw hands onto
world canvas"
].
"*make this true to flash damaged areas for testing*"
self class debugShowDamage ifTrue: [aWorld flashRects: allDamage color:
Color black].

canvas finish.
"quickly copy altered rects of canvas to Display:"
deferredUpdateMode
ifTrue: [self forceDamageToScreen: allDamage]
ifFalse: [canvas showAt: aWorld viewBox origin invalidRects: allDamage].
handsToDraw do: [:h | h restoreSavedPatchOn: canvas].  "restore world
canvas under hands"
Display deferUpdates: false; forceDisplayUpdate.

The VM will take care of throwing the bits to the display in various ways.
Interesting to look how it is done for Windows, OSX, and Linux.

So you have about a full view now.

Timing wise, there is also some interaction with the VM occuring elsewhere.
Pharo is still polling deep inside.  epoll etc isn't there yet, hence the
little idle CPU usage when doing nothing.

Good luck doing this UI trip with other platforms, not to mention change or
instrument it the way you like.

Pharo is really cool for this as it helps in learning about a lot of things.

Want to do sockets?
Do the high level stuff in Pharo and dig in the VM to see how it is done
down under for a set of platforms.

Enjoy.

Phil






123