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 On Mon, Oct 3, 2016 at 8:02 PM, p...@highoctane.be <p...@highoctane.be> wrote: > > > On Mon, Oct 3, 2016 at 6:47 PM, CodeDmitry <dimamakh...@gmail.com> wrote: > >> LOL (in GrowlMorph): >> is: rect saneWithRespectTo: morphs >> >> ^(morphs anySatisfy: [ :morph | morph owner isNotNil and: [morph >> bounds >> intersects: rect]]) not >> >> for some reason I find this method name quite amusing :3 >> > > There are interesting things in there indeed. "Intention revealing" > enough? > >> >> >> Let me guess; >> >> 1. "World defer: aBlock." defers the event to be called as soon as >> possible(not necessarily now). >> > > Actually this works for any Morph in 5.0 > > Morph>>#defer: aValuable > "aValuable will be executed in the next UI rendering cycle" > self owner > ifNotNil: [ self owner defer: aValuable] > ifNil: [ UIManager default defer: aValuable ] > > UIManager (MorphicUIManager) will do this at one point (track implementers > 'til class side in WorldState) > > defer: aValuable > "aValuable will be executed in the next UI rendering cycle" > self addDeferredUIMessage: aValuable. > > This will stick it in a queue: > > deferredUIMessages > > ^DeferredUIMessages ifNil: [DeferredUIMessages := WaitfreeQueue new]. > > and then, there is interesting black magic going on > > runStepMethodsIn: aWorld > "Perform periodic activity inbetween event cycles" > | queue nextInQueue| > "If available dispatch some deferred UI Message" > queue := self class deferredUIMessages. > > [(nextInQueue := queue nextOrNil) isNil] "<<---------------- > here all is happening -------" > whileFalse: [ nextInQueue value]. > > self runLocalStepMethodsIn: aWorld. "<<------------ step > methods -----------------" > > "The multi-threaded global Transcript needs to be updated periodically and > synchronously with the UI." > Transcript stepGlobal. > "<<------------ and *this* is some black magic for Transcript ----" > > > Fun thing: > > stepGlobal > " The superclass method Model>>step indicates a convention that might be > used to interoperate > synchronously with the UI-thread. However when multiple Transcript > windows are open, their > PluggableTextMorphs share a single instance, from the global Transcript. > To avoid potential trouble, > this method should not be named #step. > As well, we need this method to execute even when no Transcript windows > are open, so the stream > continues to be reset periodically, otherwise it would grow indefinitely. > So this method is invoked > from WorldState>>runStepMethodsIn:. > " > > "Next three lines required temporarily to initialize instance variables > added to existing instance" > deferredClear ifNil: [ deferredClear := false ]. > deferredEndEntry ifNil: [ deferredEndEntry := false ]. > stepContents ifNil: [ stepContents := '' ]. > deferredClear ifTrue: > [ deferredClear := false. > stepContents := ''. > self changed: #clearText. > ]. > deferredEndEntry ifTrue: > [ deferredEndEntry := false. > self critical: > [ stepContents := stream contents. > stream resetContents. > ]. > self changed: #appendEntry. > ]. > > Just in case one was wondering how Transcript clear actually works, check > this: > > clear > " Clear all characters by resetting the stream and voiding any previously > flagged deferredEndEntry. > Redisplays the view by signalling for #step to send #changed: . > " > self > critical: [ > deferredClear := true. "<------- magic! -------" > deferredEndEntry := false. "<------- more magic!--------" > stream reset ] > > > Good luck to infer that from scratch. > > > > > >> 2. "[Block] fork" is called immediatly, but on a new thread. >> > > Yeah, use forkNamed: aString if you actually want to track the thing > easily in the Process Browser. > > > >> 3. "<number> <time unit> wait" blocks the current thread for specific >> time >> before continuing. >> > > Right. > >> >> Now rearrange it into: >> >> [ >> 10 seconds wait. >> World defer: [ >> Transcript show: 'Hello, World!'. >> ]. >> ] fork. >> >> Into >> >> do: aBlock after: nanoTime >> [ >> 10 seconds wait. "<------- you need to say something like >> nanoTime asNanoSeconds wait. But careful as Delay works up to milliseconds >> I think, so 5 asNanoseconds asSeconds will just be zero" >> World defer: aBlock. "<-- OK, World is a WorldMorph, wich >> extends PasteUpMorph, the old World class in Pharo 3.x" >> ] fork. >> >> I guess that all of this shows that there is some flexibility in Pharo > async. > > Check the Generator class for some brain twisting with fork. > > Run > > Generator examplePrimes. > > for a start. > > Phil > >> >> >> -- >> View this message in context: http://forum.world.st/Intro-to >> -Microsoft-COM-for-Smalltalkers-tp4917738p4917913.html >> Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com. >> >> >> >