[squeak-dev] The Trunk: Morphic-mt.1697.mcz

commits at source.squeak.org commits at source.squeak.org
Thu Oct 8 15:12:32 UTC 2020


Marcel Taeumel uploaded a new version of Morphic to project The Trunk:
http://source.squeak.org/trunk/Morphic-mt.1697.mcz

==================== Summary ====================

Name: Morphic-mt.1697
Author: mt
Time: 8 October 2020, 5:12:27.351452 pm
UUID: 09479921-7aa2-5e4b-b9d9-6b07134b2372
Ancestors: Morphic-mt.1696

Refactoring global Active(World|Hand|Event) variables to be actual DynamicVariable's. Step 1 of 2 -- Core refactoring to check whether system stays functional. All remaining references to the Active(World|Hand|Event) globals will be removed in a second step.

See: http://forum.world.st/Changeset-Eliminating-global-state-from-Morphic-td5121690.html

=============== Diff against Morphic-mt.1696 ===============

Item was changed:
+ (PackageInfo named: 'Morphic') preamble: '"Turn off Morphic drawing because we are refactoring ActiveWorld, ActiveHand, and ActiveEvent."
+ Project current world setProperty: #shouldDisplayWorld toValue: false.'!
- (PackageInfo named: 'Morphic') preamble: 'PluggableListMorph allSubInstancesDo: [:m |
- 	m listMorph cellInset: 3 at 0].'!

Item was added:
+ DynamicVariable subclass: #ActiveEventVariable
+ 	instanceVariableNames: ''
+ 	classVariableNames: ''
+ 	poolDictionaries: ''
+ 	category: 'Morphic-Worlds'!

Item was added:
+ ----- Method: ActiveEventVariable class>>default (in category 'accessing') -----
+ default
+ 
+ 	^ self currentHand ifNotNil: [:hand | hand lastEvent]!

Item was added:
+ ----- Method: ActiveEventVariable class>>value:during: (in category 'accessing') -----
+ value: anObject during: aBlock
+ 	"For backword compatibility with 5.3 and earlier, still maintain the original global variable."
+ 
+ 	| priorEvent |
+ 	priorEvent := self value.
+ 	ActiveEvent := anObject.
+ 	^ [super value: anObject during: aBlock] ensure: [
+ 		ActiveEvent == anObject ifTrue: [ActiveEvent := priorEvent]]!

Item was added:
+ DynamicVariable subclass: #ActiveHandVariable
+ 	instanceVariableNames: ''
+ 	classVariableNames: ''
+ 	poolDictionaries: ''
+ 	category: 'Morphic-Worlds'!

Item was added:
+ ----- Method: ActiveHandVariable class>>default (in category 'accessing') -----
+ default
+ 
+ 	^ self currentWorld primaryHand!

Item was added:
+ ----- Method: ActiveHandVariable class>>value:during: (in category 'accessing') -----
+ value: anObject during: aBlock
+ 	"For backword compatibility with 5.3 and earlier, still maintain the original global variable."
+ 	
+ 	| priorHand |
+ 	priorHand := self value.
+ 	ActiveHand := anObject.
+ 	^ [super value: anObject during: aBlock] ensure: [
+ 		ActiveHand == anObject ifTrue: [ActiveHand := priorHand]]!

Item was added:
+ DynamicVariable subclass: #ActiveWorldVariable
+ 	instanceVariableNames: ''
+ 	classVariableNames: ''
+ 	poolDictionaries: ''
+ 	category: 'Morphic-Worlds'!

Item was added:
+ ----- Method: ActiveWorldVariable class>>default (in category 'accessing') -----
+ default
+ 
+ 	^ Project current world!

Item was added:
+ ----- Method: ActiveWorldVariable class>>value:during: (in category 'accessing') -----
+ value: anObject during: aBlock
+ 	"For backword compatibility with 5.3 and earlier, still maintain the original global variable."
+ 
+ 	| priorWorld |
+ 	priorWorld := self value.
+ 	ActiveWorld := anObject.
+ 	^ [super value: anObject during: aBlock] ensure: [
+ 		ActiveWorld == anObject ifTrue: [ActiveWorld := priorWorld]]!

Item was changed:
  ----- Method: HandMorph>>becomeActiveDuring: (in category 'initialization') -----
  becomeActiveDuring: aBlock
+ 	"Make the receiver the active hand during the evaluation of aBlock."
- 	"Make the receiver the ActiveHand during the evaluation of aBlock."
  
+ 	^ ActiveHandVariable value: self during: aBlock!
- 	| priorHand |
- 	priorHand := ActiveHand.
- 	ActiveHand := self.
- 	^ aBlock ensure: [
- 		"check to support project switching."
- 		ActiveHand == self ifTrue: [ActiveHand := priorHand]].!

Item was changed:
  ----- Method: HandMorph>>processEvents (in category 'event handling') -----
  processEvents
  	"Process user input events from the local input devices."
  
  	| evt evtBuf type hadAny |
+ 	self currentEvent ~= lastMouseEvent ifTrue: [
+ 		"Meaning that we were invoked from within an event response.
+ 		Make sure z-order is up to date."
+ 		self mouseOverHandler processMouseOver: lastMouseEvent].
+ 	
- 	ActiveEvent ifNotNil: 
- 			["Meaning that we were invoked from within an event response.
- 		Make sure z-order is up to date"
- 
- 			self mouseOverHandler processMouseOver: lastMouseEvent].
  	hadAny := false.
  	[(evtBuf := Sensor nextEvent) isNil] whileFalse: 
  			[evt := nil.	"for unknown event types"
  			type := evtBuf first.
  			type = EventTypeMouse
  				ifTrue: [evt := self generateMouseEvent: evtBuf].
  			type = EventTypeMouseWheel
  				ifTrue: [evt := self generateMouseWheelEvent: evtBuf].
  			type = EventTypeKeyboard 
  				ifTrue: [evt := self generateKeyboardEvent: evtBuf].
  			type = EventTypeDragDropFiles 
  				ifTrue: [evt := self generateDropFilesEvent: evtBuf].
  			type = EventTypeWindow
  				ifTrue:[evt := self generateWindowEvent: evtBuf].
  			"All other events are ignored"
  			(type ~= EventTypeDragDropFiles and: [evt isNil]) ifTrue: [^self].
+ 			evt ifNotNil: ["Finally, handle it."
- 			evt isNil 
- 				ifFalse: 
- 					["Finally, handle it"
- 
  					self handleEvent: evt.
  					hadAny := true.
+ 					
- 
  					"For better user feedback, return immediately after a mouse event has been processed."
+ 					evt isMouse ifTrue: [^ self]]].
+ 	
- 					evt isMouse ifTrue: [^self]]].
  	"note: if we come here we didn't have any mouse events"
+ 	mouseClickState ifNotNil: [
+ 		"No mouse events during this cycle. Make sure click states time out accordingly"
+ 		mouseClickState handleEvent: lastMouseEvent asMouseMove from: self].
+ 	hadAny ifFalse: [
+ 		"No pending events. Make sure z-order is up to date"
+ 		self mouseOverHandler processMouseOver: lastMouseEvent].!
- 	mouseClickState notNil 
- 		ifTrue: 
- 			["No mouse events during this cycle. Make sure click states time out accordingly"
- 
- 			mouseClickState handleEvent: lastMouseEvent asMouseMove from: self].
- 	hadAny 
- 		ifFalse: 
- 			["No pending events. Make sure z-order is up to date"
- 
- 			self mouseOverHandler processMouseOver: lastMouseEvent]!

Item was changed:
  ----- Method: Morph>>activeHand (in category 'structure') -----
  activeHand
+ 
+ 	self flag: #deprecated. "mt: Use #currentHand instead."
+ 	^ self currentHand!
- 	
- 	^ ActiveHand ifNil: [
- 		self isInWorld
- 			ifTrue: [self world activeHand]
- 			ifFalse: [nil]]!

Item was changed:
  ----- Method: Morph>>primaryHand (in category 'structure') -----
  primaryHand
  
+ 	^ self currentWorld primaryHand!
-         | outer |
-         outer := self outermostWorldMorph ifNil: [^ nil].
-         ^ outer activeHand ifNil: [outer firstHand]!

Item was changed:
  ----- Method: MorphicEvent>>becomeActiveDuring: (in category 'initialize') -----
  becomeActiveDuring: aBlock
+ 	"Make the receiver the active event during the evaluation of aBlock."
- 	"Make the receiver the ActiveEvent during the evaluation of aBlock."
  
+ 	^ ActiveEventVariable value: self during: aBlock!
- 	| priorEvent |
- 	priorEvent := ActiveEvent.
- 	ActiveEvent := self.
- 	^ aBlock ensure: [
- 		"check to support project switching."
- 		ActiveEvent == self ifTrue: [ActiveEvent := priorEvent]].!

Item was changed:
  ----- Method: MorphicProject>>interruptCleanUpFor: (in category 'scheduling & debugging') -----
  interruptCleanUpFor: interruptedProcess
  	"Clean up things in case of a process interrupt."
  
  	super interruptCleanUpFor: interruptedProcess.
  
  	self uiProcess == interruptedProcess ifTrue: [
+ 		self currentHand ifNotNil: [:hand | hand interrupted].
- 		ActiveHand ifNotNil: [ActiveHand interrupted].
- 		ActiveWorld := world. "reinstall active globals"
- 		ActiveHand := world primaryHand.
- 		ActiveHand interrupted. "make sure this one's interrupted too"
- 		ActiveEvent := nil.
- 		
  		world removeProperty: #shouldDisplayWorld.
+ 		Preferences eToyFriendly ifTrue: [world stopRunningAll]].!
- 		
- 		Preferences eToyFriendly
- 			ifTrue: [world stopRunningAll]].!

Item was changed:
+ ----- Method: Object>>currentEvent (in category '*Morphic-Kernel-accessing') -----
- ----- Method: Object>>currentEvent (in category '*Morphic-Kernel') -----
  currentEvent
+ 	"Answer the current MorphicEvent. Provided that a morphic project is loaded, this method never returns nil."
+ 	
+ 	^ ActiveEventVariable value!
- 	"Answer the current Morphic event.  This method never returns nil."
- 	^ActiveEvent ifNil:[self currentHand lastEvent]!

Item was changed:
+ ----- Method: Object>>currentHand (in category '*Morphic-Kernel-accessing') -----
- ----- Method: Object>>currentHand (in category '*Morphic-Kernel') -----
  currentHand
+ 	"Answer the current HandMorph. Provided that a morphic project is loaded, this method will never return nil."
- 	"Return a usable HandMorph -- the one associated with the object's current environment.  This method will always return a hand, even if it has to conjure one up as a last resort.  If a particular hand is actually handling events at the moment (such as a remote hand or a ghost hand), it will be returned."
  
+ 	^ Project current isMorphic
+ 		ifTrue: [ActiveHandVariable value]
+ 		ifFalse: [Sensor "MVC/ST80 fallback"]!
- 	^ActiveHand ifNil: [ self currentWorld primaryHand ]!

Item was changed:
+ ----- Method: Object>>currentWorld (in category '*Morphic-Kernel-accessing') -----
- ----- Method: Object>>currentWorld (in category '*Morphic-Kernel') -----
  currentWorld
+ 	"Answer the current world. This method will never return nil."
+ 
+ 	^ ActiveWorldVariable value!
- 	"Answer a morphic world that is the current UI focus."
- 	^ActiveWorld ifNil:[Project current world]!

Item was removed:
- ----- Method: PasteUpMorph>>activeHand (in category 'structure') -----
- activeHand
- 
- 	^ worldState
- 		ifNotNil: [:ws | ws activeHand ifNil: [ws hands first]]
- 		ifNil: [super activeHand]!

Item was removed:
- ----- Method: PasteUpMorph>>activeHand: (in category 'world state') -----
- activeHand: aHandMorph
- 	"temporarily retained for old main event loops"
- 
- 	worldState activeHand: aHandMorph.
- 
- !

Item was changed:
  ----- Method: PasteUpMorph>>becomeActiveDuring: (in category 'initialization') -----
  becomeActiveDuring: aBlock
+ 	"Make the receiver the active world during the evaluation of aBlock."
- 	"Make the receiver the ActiveWorld during the evaluation of aBlock."
  
+ 	^ ActiveWorldVariable value: self during: aBlock!
- 	| priorWorld |
- 	priorWorld := ActiveWorld.
- 	ActiveWorld := self.
- 	^ aBlock ensure: [
- 		"check to support project switching."
- 		ActiveWorld == self ifTrue: [ActiveWorld := priorWorld]].!

Item was changed:
  ----- Method: PasteUpMorph>>install (in category 'world state') -----
  install
+ 
  	owner := nil.	"since we may have been inside another world previously"
+ 	
- 	ActiveWorld := self.
- 	ActiveHand := self hands first.	"default"
- 	ActiveEvent := nil.
  	submorphs do: [:ss | ss owner isNil ifTrue: [ss privateOwner: self]].
  	"Transcript that was in outPointers and then got deleted."
  	self viewBox: Display boundingBox.
  	EventSensor default flushEvents.
  	worldState handsDo: [:h | h initForEvents].
  	self installFlaps.
  	self borderWidth: 0.	"default"
  	(Preferences showSecurityStatus 
  		and: [SecurityManager default isInRestrictedMode]) 
  			ifTrue: 
  				[self
  					borderWidth: 2;
  					borderColor: Color red].
  	self presenter allExtantPlayers do: [:player | player prepareToBeRunning].
  	SystemWindow noteTopWindowIn: self.!

Item was added:
+ ----- Method: PasteUpMorph>>primaryHand (in category 'structure') -----
+ primaryHand
+ 
+ 	^ self hands at: 1 ifAbsent: [nil]!

Item was changed:
  ----- Method: PasteUpMorph>>processEvent:using: (in category 'events-processing') -----
  processEvent: anEvent using: defaultDispatcher
+ 	"Reimplemented to install the receiver as the new active world if it is one"
+ 
+ 	self isWorldMorph ifFalse: [
+ 		^ super processEvent: anEvent using: defaultDispatcher].
+ 	
+ 	^ self becomeActiveDuring: [
+ 		super processEvent: anEvent using: defaultDispatcher]!
- 	"Reimplemented to install the receiver as the new ActiveWorld if it is one"
- 	| priorWorld result |
- 	self isWorldMorph ifFalse:[^super processEvent: anEvent using: defaultDispatcher].
- 	priorWorld := ActiveWorld.
- 	ActiveWorld := self.
- 	[result := super processEvent: anEvent using: defaultDispatcher]
- 		ensure: [ActiveWorld := priorWorld].
- 	^result
- !

Item was removed:
- ----- Method: WorldState>>activeHand (in category 'hands') -----
- activeHand
- 
- 	^ ActiveHand!

Item was changed:
  ----- Method: WorldState>>doOneCycleNowFor: (in category 'update cycle') -----
  doOneCycleNowFor: aWorld
  	"Immediately do one cycle of the interaction loop.
  	This should not be called directly, but only via doOneCycleFor:"
  
  	| capturingGesture |
  	DisplayScreen checkForNewScreenSize.
  	capturingGesture := false.
  	"self flag: #bob.	"	"need to consider remote hands in lower worlds"
+ 	
- 
  	"process user input events"
  	LastCycleTime := Time millisecondClockValue.
+ 	self handsDo: [:hand |
+ 		hand becomeActiveDuring: [
+ 			hand processEvents.
+ 			capturingGesture := capturingGesture or: [hand isCapturingGesturePoints]]].
+ 	
- 	self handsDo: [:h |
- 		ActiveHand := h.
- 		h processEvents.
- 		capturingGesture := capturingGesture or: [ h isCapturingGesturePoints ].
- 		ActiveHand := nil
- 	].
- 
- 	"the default is the primary hand"
- 	ActiveHand := self hands first.
- 
  	"The gesture recognizer needs enough points to be accurate.
  	Therefore morph stepping is disabled while capturing points for the recognizer"
+ 	capturingGesture ifFalse: [
+ 		aWorld runStepMethods.		"there are currently some variations here"
+ 		self displayWorldSafely: aWorld].!
- 	capturingGesture ifFalse: 
- 		[aWorld runStepMethods.		"there are currently some variations here"
- 		self displayWorldSafely: aWorld].
- !

Item was changed:
  ----- Method: WorldState>>doOneSubCycleFor: (in category 'update cycle') -----
  doOneSubCycleFor: aWorld
- 	"Like doOneCycle, but preserves activeHand."
  
+ 	self flag: #deprecate. "ct: Historically, global state was preserved here. Since the introduction of ActiveHandVariable, this is no longer necessary, so this is equivalent to #doOneCycleFor:. However, let's keep this possibly valuable hook for now."
+ 
+ 	^ self doOneCycleFor: aWorld!
- 	| currentHand |
- 	currentHand := ActiveHand.
- 	self doOneCycleFor: aWorld.
- 	ActiveHand := currentHand!

Item was added:
+ ----- Method: WorldState>>primaryHand (in category 'hands') -----
+ primaryHand
+ 
+ 	self flag: #deprecated. "ct: Send #primaryHand to #currentWorld instead."
+ 	^ self currentWorld primaryHand!

Item was changed:
  ----- Method: WorldState>>removeHand: (in category 'hands') -----
  removeHand: aHandMorph
  	"Remove the given hand from the list of hands for this world."
  
+ 	(hands includes: aHandMorph) ifFalse: [^ self].
+ 	self currentHand == aHandMorph ifTrue: [
+ 		self flag: #invalidate. "ct: Should we try to clear ActiveHandVariable here or doesn't this matter? In past, ActiveHand was set to nil at this point."].
+ 	hands := hands copyWithout: aHandMorph.!
- 	(hands includes: aHandMorph) ifFalse: [^self].
- 	hands := hands copyWithout: aHandMorph.
- 	ActiveHand == aHandMorph ifTrue: [ActiveHand := nil].
- !

Item was changed:
  ----- Method: WorldState>>runLocalStepMethodsIn: (in category 'stepping') -----
  runLocalStepMethodsIn: aWorld 
  	"Run morph 'step' methods (LOCAL TO THIS WORLD) whose time has come. Purge any morphs that are no longer in this world.
  	ar 3/13/1999: Remove buggy morphs from the step list so that they don't raise repeated errors."
  
+ 	| now morphToStep stepTime |
- 	| now morphToStep stepTime priorWorld |
  	now := Time millisecondClockValue.
+ 	
+ 	aWorld becomeActiveDuring: [ 
+ 		self triggerAlarmsBefore: now.
+ 		
+ 		stepList ifEmpty: [^ self].
+ 		
+ 		(now < lastStepTime or: [now - lastStepTime > 5000]) ifTrue: [
+ 			self adjustWakeupTimes: now].	"clock slipped"
+ 		
+ 		[stepList notEmpty and: [stepList first scheduledTime < now]] whileTrue: [
+ 			lastStepMessage := stepList removeFirst.
- 	priorWorld := ActiveWorld.
- 	ActiveWorld := aWorld.
- 	self triggerAlarmsBefore: now.
- 	stepList isEmpty 
- 		ifTrue: 
- 			[ActiveWorld := priorWorld.
- 			^self].
- 	(now < lastStepTime or: [now - lastStepTime > 5000]) 
- 		ifTrue: [self adjustWakeupTimes: now].	"clock slipped"
- 	[stepList isEmpty not and: [stepList first scheduledTime < now]] 
- 		whileTrue: 
- 			[lastStepMessage := stepList removeFirst.
  			morphToStep := lastStepMessage receiver.
+ 			(morphToStep shouldGetStepsFrom: aWorld) ifTrue: [
+ 				lastStepMessage value: now.
+ 				lastStepMessage ifNotNil: [
+ 					stepTime := lastStepMessage stepTime ifNil: [morphToStep stepTime].
+ 					lastStepMessage scheduledTime: now + (stepTime max: 1).
+ 					stepList add: lastStepMessage]].
- 			(morphToStep shouldGetStepsFrom: aWorld) 
- 				ifTrue: 
- 					[lastStepMessage value: now.
- 					lastStepMessage ifNotNil: 
- 							[stepTime := lastStepMessage stepTime ifNil: [morphToStep stepTime].
- 							lastStepMessage scheduledTime: now + (stepTime max: 1).
- 							stepList add: lastStepMessage]].
  			lastStepMessage := nil].
+ 		
+ 		lastStepTime := now].!
- 	lastStepTime := now.
- 	ActiveWorld := priorWorld!

Item was changed:
+ (PackageInfo named: 'Morphic') postscript: '"Turn on Morphic drawing again."
+ Project current world removeProperty: #shouldDisplayWorld.'!
- (PackageInfo named: 'Morphic') postscript: 'Smalltalk removeFromStartUpList: PasteUpMorph.
- Smalltalk removeFromShutDownList: PasteUpMorph.'!



More information about the Squeak-dev mailing list