[squeak-dev] The Inbox: Morphic-ct.1991.mcz

commits at source.squeak.org commits at source.squeak.org
Wed May 18 11:15:30 UTC 2022


A new version of Morphic was added to project The Inbox:
http://source.squeak.org/inbox/Morphic-ct.1991.mcz

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

Name: Morphic-ct.1991
Author: ct
Time: 18 May 2022, 1:15:26.246371 pm
UUID: 8c165900-282b-4b69-93c0-e61b23b4f6fd
Ancestors: Morphic-nice.1989

Increases robustness of #windowHostFocusMorph to honor some facts:

- Currently, there is no exact-once guarantee by the VM for the recording of #windowActivated and #windowDeactived events.
- It is also possible that new morphs temporarily change the keyboard focus while the host focus morph is active, e.g., dialog windows due to an asynchronous operation or an attempt to close the VM window while it is not active (actually, some window managers always disable the window when closing it via the taskbar/Alt + F4).

To fix this, extract the host focus as a class (WindowHostFocusMorph) that overrides #keyboardFocusDelegate. When another client stores the keyboard focus before changing it (for instance, see priorKeyboardFocus in DialogWindow>>#getUserResponse), any attempt to restore that focus later will pass it back to the original previousFocus. Before resetting the keyboard focus on #windowActivate:, make sure that the host focus morph still has the keyboard focus.

Please test again with all your crazy window managers and shortcuts out there. =)

Thanks to Chris (cmm) for the report and Marcel (mt) for the help!

=============== Diff against Morphic-nice.1989 ===============

Item was changed:
  ----- Method: PasteUpMorph>>windowEvent: (in category 'event handling') -----
  windowEvent: anEvent
+ 
  	self windowEventHandler
  		ifNotNil: [^self windowEventHandler windowEvent: anEvent].
+ 	
- 
  	anEvent type
  		caseOf: {
  			[#windowClose] -> [
  				Preferences eToyFriendly 
  					ifTrue: [ProjectNavigationMorph basicNew quitSqueak]
  					ifFalse: [TheWorldMenu basicNew quitSession]].
  			
  			[#windowDeactivated]	-> [
+ 				"The host window has been deactivated. Until it regains the focus, honor the fact that we will not receive keyboard events again by changing the current keyboard focus morph. windowHostFocusMorph represents the host system which now holds the keyboard focus instead of the previousFocus. If enabled, disable #mouseOverForKeyboardFocus temporarily because when inactive, we *can't* set the externally controlled keyboard focus."
+ 				(self valueOfProperty: #windowHostFocusMorph) ifNotNil: [:hostFocus |
+ 					"There is currently no exact-once guarantee for this event type from the VM. Mark any older host focus morph as inactive, it will be held as the previousFocus of the next host focus morph."
+ 					hostFocus active: false].
+ 				self setProperty: #windowHostFocusMorph toValue: (WindowHostFocusMorph new
+ 					in: [:hostFocus |
+ 						hostFocus previousFocus: anEvent hand keyboardFocus.
+ 						anEvent hand newKeyboardFocus: hostFocus.
+ 						Preferences mouseOverForKeyboardFocus ifTrue: [
+ 							hostFocus previousMouseOverForKeyboardFocus: true.
+ 							Preferences setPreference: #mouseOverForKeyboardFocus toValue: false]];
+ 					yourself)].
- 				"The host window has been deactivated. Until it regains the focus, honor the fact that we will not receive keyboard events again by changing the current keyboard focus morph. windowHostFocusMorph represents the host system which now holds the keyboard focus instead of the previousFocus. If enabled, disable #mouseOverForKeyboardFocus temporarily because when inactive, we *can't* set the keyboard focus."
- 				(self valueOfProperty: #windowHostFocusMorph ifAbsentPut: [
- 					Morph new
- 						name: #windowHostFocusMorph;
- 						yourself]) in: [:hostFocus |
- 					hostFocus setProperty: #previousFocus toValue: anEvent hand keyboardFocus.
- 					anEvent hand newKeyboardFocus: hostFocus.
- 					Preferences mouseOverForKeyboardFocus ifTrue: [
- 						hostFocus setProperty: #previousMouseOverForKeyboardFocus toValue: true.
- 						Preferences setPreference: #mouseOverForKeyboardFocus toValue: false]]].
  			[#windowActivated] -> [
  				"Alright, the spook is over!! We have back control over the keyboard focus, delete the windowHostFocusMorph and restore the previous focus holder and the #mouseOverForKeyboardFocus preference."
+ 				(self removeProperty: #windowHostFocusMorph) ifNotNil: [:hostFocus |
+ 					hostFocus active: false.
+ 					(anEvent hand keyboardFocus == hostFocus and: [hostFocus previousFocus notNil]) ifTrue:
+ 						[anEvent hand newKeyboardFocus: hostFocus previousFocus].
+ 					hostFocus previousMouseOverForKeyboardFocus ifNotNil: [:value |
+ 						Preferences setPreference: #mouseOverForKeyboardFocus toValue: value]]]. }
- 				self valueOfProperty: #windowHostFocusMorph ifPresentDo: [:hostFocus |
- 					hostFocus abandon.
- 					(hostFocus valueOfProperty: #previousFocus) ifNotNil: [:previousFocus |
- 						anEvent hand newKeyboardFocus: previousFocus].
- 					(hostFocus valueOfProperty: #previousMouseOverForKeyboardFocus) ifNotNil: [:value |
- 						Preferences setPreference: #mouseOverForKeyboardFocus toValue: value].
- 					self removeProperty: #windowHostFocusMorph]]. }
  		otherwise: []!

Item was added:
+ Morph subclass: #WindowHostFocusMorph
+ 	instanceVariableNames: 'active previousFocus previousMouseOverForKeyboardFocus'
+ 	classVariableNames: ''
+ 	poolDictionaries: ''
+ 	category: 'Morphic-Worlds'!
+ 
+ !WindowHostFocusMorph commentStamp: 'ct 5/18/2022 12:41' prior: 0!
+ I represent the host system as a focus holder, i.e., I receive the keyboard focus when the VM looses the keyboard focus. See PasteUpMorph>>#windowEvent:.!

Item was added:
+ ----- Method: WindowHostFocusMorph>>active (in category 'accessing') -----
+ active
+ 
+ 	^ active!

Item was added:
+ ----- Method: WindowHostFocusMorph>>active: (in category 'accessing') -----
+ active: aBoolean
+ 
+ 	active := aBoolean.!

Item was added:
+ ----- Method: WindowHostFocusMorph>>initialize (in category 'initialization') -----
+ initialize
+ 
+ 	super initialize.
+ 	
+ 	self active: true.!

Item was added:
+ ----- Method: WindowHostFocusMorph>>keyboardFocusDelegate (in category 'event handling') -----
+ keyboardFocusDelegate
+ 	"When the receiver was remembered as a prior keyboard focus in place of the previous focus morph, answer that previous morph as a keyboard focus delegate so that re-passing the focus to it works. For instance, this happens when a DialogWindow is invoked while the VM does not have the keyboard focus (e.g., when attempting to close the VM window from the outside)."
+ 	
+ 	self flag: #forLater. "Preferably, we would even *prevent* other morphs from receiving the keyboard focus through this surrogate. However, there is currently no hook #okToChangeKeyboardFocus: in HandMorph>>#newKeyboardFocus: and re-setting the focus unagreedly might cause trouble in other focus holders."
+ 
+ 	self active ifTrue: [^ self].
+ 	^ self previousFocus ifNotNil: [:morph | morph keyboardFocusDelegate]!

Item was added:
+ ----- Method: WindowHostFocusMorph>>previousFocus (in category 'accessing') -----
+ previousFocus
+ 
+ 	^ previousFocus!

Item was added:
+ ----- Method: WindowHostFocusMorph>>previousFocus: (in category 'accessing') -----
+ previousFocus: aMorph
+ 
+ 	previousFocus := aMorph.!

Item was added:
+ ----- Method: WindowHostFocusMorph>>previousMouseOverForKeyboardFocus (in category 'accessing') -----
+ previousMouseOverForKeyboardFocus
+ 
+ 	^ previousMouseOverForKeyboardFocus!

Item was added:
+ ----- Method: WindowHostFocusMorph>>previousMouseOverForKeyboardFocus: (in category 'accessing') -----
+ previousMouseOverForKeyboardFocus: aBoolean
+ 
+ 	previousMouseOverForKeyboardFocus := aBoolean.!



More information about the Squeak-dev mailing list