WindowGroup.st
changeset 244 83218faf792c
parent 221 013252f3a7e5
child 251 915de9a65169
--- a/WindowGroup.st	Thu Nov 23 03:29:10 1995 +0100
+++ b/WindowGroup.st	Thu Nov 23 11:38:43 1995 +0100
@@ -11,8 +11,8 @@
 "
 
 Object subclass:#WindowGroup
-	 instanceVariableNames:'views topViews myProcess mySensor isModal previousGroup 
-				focusView focusSequence preEventHook postEventHook'
+	 instanceVariableNames:'views topViews myProcess mySensor isModal previousGroup focusView
+                focusSequence preEventHook postEventHook'
 	 classVariableNames:'LastActiveGroup LastActiveProcess LeaveSignal'
 	 poolDictionaries:''
 	 category:'Interface-Support'
@@ -34,10 +34,6 @@
 "
 !
 
-version
-    ^ '$Header: /cvs/stx/stx/libview/WindowGroup.st,v 1.35 1995-11-13 17:11:01 cg Exp $'
-!
-
 documentation
 "
     In Smalltalk/X, the known (ST-80) concept of a controller has been
@@ -127,6 +123,10 @@
     For more information, read 'introduction to view programming' in the
     doc/online directory.
 "
+!
+
+version
+    ^ '$Header: /cvs/stx/stx/libview/WindowGroup.st,v 1.36 1995-11-23 10:38:24 cg Exp $'
 ! !
 
 !WindowGroup class methodsFor:'initialization'!
@@ -141,6 +141,14 @@
     "WindowGroup initialize"
 ! !
 
+!WindowGroup class methodsFor:'instance creation'!
+
+new
+    "create and return a new WindowGroup object"
+
+    ^ self basicNew initialize
+! !
+
 !WindowGroup class methodsFor:'Signal constants'!
 
 leaveSignal
@@ -152,14 +160,6 @@
     ^ LeaveSignal
 ! !
 
-!WindowGroup class methodsFor:'instance creation'!
-
-new
-    "create and return a new WindowGroup object"
-
-    ^ self basicNew initialize
-! !
-
 !WindowGroup class methodsFor:'accessing'!
 
 activeGroup
@@ -212,14 +212,6 @@
     "Modified: 3.9.1995 / 14:49:53 / claus"
 !
 
-setActiveGroup:aGroup
-    "set the currently active windowGroup.
-     Temporary; do not use this interface, it will vanish."
-
-    LastActiveProcess := Processor activeProcess.
-    LastActiveGroup := aGroup
-!
-
 scheduledWindowGroups
     "return a collection of all windowGroups (possibly for different
      display devices) which are scheduled (i.e. which have a process 
@@ -249,14 +241,25 @@
     "
 
     "Modified: 1.9.1995 / 13:43:09 / claus"
+!
+
+setActiveGroup:aGroup
+    "set the currently active windowGroup.
+     Temporary; do not use this interface, it will vanish."
+
+    LastActiveProcess := Processor activeProcess.
+    LastActiveGroup := aGroup
 ! !
 
 !WindowGroup methodsFor:'accessing'!
 
-sensor
-    "return the windowGroups sensor"
+addTopView:aView
+    "add a topview to the group"
 
-    ^ mySensor
+    topViews isNil ifTrue:[
+	topViews := OrderedCollection new.
+    ].
+    topViews add:aView
 !
 
 addView:aView
@@ -268,13 +271,57 @@
     views add:aView
 !
 
-addTopView:aView
-    "add a topview to the group"
+isModal
+    "return true, if I am in a modal mode"
+
+    ^ isModal
+!
+
+mainGroup
+    "return the main windowgroup 
+     (that is the top one, which is not modal).
+     There is one exception to this: the debugger (which is sort of modal)
+     returns itself as mainGroup (not its debuggee)."
+
+    |g prev|
+
+    g := self.
+    [g notNil and:[g isModal and:[(prev := g previousGroup) notNil]]] whileTrue:[
+	g := prev
+    ].
+    ^ g
+
+    "Modified: 3.9.1995 / 14:57:20 / claus"
+!
 
-    topViews isNil ifTrue:[
-	topViews := OrderedCollection new.
-    ].
-    topViews add:aView
+postEventHook:anObject 
+    "set the postEventHook - this one will get all events
+     passed after being processed here (via #processEvent:)."
+
+    postEventHook := anObject
+!
+
+preEventHook:anObject 
+    "set the preEventHook - this one will get all events
+     passed before being processed here (via #processEvent:).
+     If this returns true, the event is supposed to be already
+     processed and ignored here.
+     Otherwise, it is processed as usual."
+
+    preEventHook := anObject
+!
+
+previousGroup
+    "return the windowgroup that started this group.
+     (for modal groups only)"
+
+    ^ previousGroup
+!
+
+process 
+    "return the windowGroups process"
+
+    ^ myProcess
 !
 
 removeView:aView
@@ -303,52 +350,10 @@
     mySensor notNil ifTrue:[mySensor eventSemaphore signal]
 !
 
-views
-    "return the views accociated to this windowGroup"
-
-    ^ views
-!
-
-topViews
-    "return the topviews accociated to this windowGroup"
-
-    ^ topViews
-!
-
-process 
-    "return the windowGroups process"
-
-    ^ myProcess
-!
-
-isModal
-    "return true, if I am in a modal mode"
+sensor
+    "return the windowGroups sensor"
 
-    ^ isModal
-!
-
-previousGroup
-    "return the windowgroup that started this group.
-     (for modal groups only)"
-
-    ^ previousGroup
-!
-
-mainGroup
-    "return the main windowgroup 
-     (that is the top one, which is not modal).
-     There is one exception to this: the debugger (which is sort of modal)
-     returns itself as mainGroup (not its debuggee)."
-
-    |g prev|
-
-    g := self.
-    [g notNil and:[g isModal and:[(prev := g previousGroup) notNil]]] whileTrue:[
-	g := prev
-    ].
-    ^ g
-
-    "Modified: 3.9.1995 / 14:57:20 / claus"
+    ^ mySensor
 !
 
 sensor:aSensor
@@ -357,64 +362,156 @@
     mySensor := aSensor
 !
 
-preEventHook:anObject 
-    "set the preEventHook - this one will get all events
-     passed before being processed here (via #processEvent:).
-     If this returns true, the event is supposed to be already
-     processed and ignored here.
-     Otherwise, it is processed as usual."
+topViews
+    "return the topviews accociated to this windowGroup"
 
-    preEventHook := anObject
+    ^ topViews
 !
 
-postEventHook:anObject 
-    "set the postEventHook - this one will get all events
-     passed after being processed here (via #processEvent:)."
+views
+    "return the views accociated to this windowGroup"
 
-    postEventHook := anObject
+    ^ views
 ! !
 
-!WindowGroup methodsFor:'special accessing'!
+!WindowGroup methodsFor:'activation / deactivation'!
+
+closeDownViews
+    "destroy all views associated to this window group"
+
+    topViews notNil ifTrue:[
+	topViews do:[:aTopView | aTopView destroy]
+    ].
+    views := nil.
+    topViews := nil.
+    mySensor := nil.
+!
+
+realizeTopViews:isRestart
+    "realize all topViews associated to this windowGroup.
+     If this is a restart, tell topViews about it."
+
+    topViews notNil ifTrue:[
+	topViews do:[:aView |
+	    aView realize.
+	    isRestart ifTrue:[
+		aView restarted
+	    ]
+	].
+    ].
+!
 
-setPreviousGroup:aGroup
-    "special entry for debugger:
-     set the windowgroup that started this group (for modal groups only).
-     This is not a public interface."
+restart
+    "restart after a snapin."
 
-    previousGroup := aGroup
+    topViews notNil ifTrue:[
+	"
+	 need a new semaphore, since obsolete processes 
+	 (from our previous live) may still sit on the current semaphore
+	"
+	mySensor eventSemaphore:Semaphore new.
+	isModal ifFalse:[
+	    self startup:true 
+	]
+    ]
+!
 
-    "Modified: 3.9.1995 / 14:55:40 / claus"
+shutdown
+    "shutdow the window group; close all views and
+     terminate process"
+
+    |p|
+
+    self closeDownViews.
+    myProcess notNil ifTrue:[
+	p := myProcess.
+	myProcess := nil.
+	p terminate.
+    ]
 !
 
-setModal:aBoolean
-    "special entry for debugger: set the modal flag.
-     Not for public use"
+startup:isRestart
+    "startup the window-group;
+     this creates a new window group process, which
+     does the event processing."
+
+    |top nm dev devNm|
+
+    previousGroup := nil.
+    myProcess isNil ifTrue:[
+	isModal := false.
+	myProcess := [
+	    self realizeTopViews:isRestart.
+	    self eventLoopWhile:[true] onLeave:[]
+	] forkAt:Processor userSchedulingPriority.
 
-    isModal := aBoolean
+	(topViews notNil and:[topViews isEmpty not]) ifTrue:[
+	    "
+	     give the handler process a user friendly name
+	    "
+	    top := topViews first.
+	    nm := top processName.
+	    (dev := top device) notNil ifTrue:[
+		devNm := dev displayName.
+		(devNm notNil and:[devNm ~= Display displayName]) ifTrue:[
+		    nm := nm , ' (' , devNm , ')'
+		]
+	    ]
+	] ifFalse:[
+	    nm := 'window handler'.
+	].
+	myProcess name:nm.
 
-    "Modified: 3.9.1995 / 14:51:04 / claus"
+	"when the process dies, we have to close-down
+	 the views as well
+	"
+	myProcess exitAction:[self closeDownViews]
+    ]
 !
 
-setProcess:aProcess 
-    "special entry for debugger: set the windowGroups process.
-     Not for public use."
+startupModal:checkBlock
+    "startup the window-group in a modal loop (i.e. under the
+     currently running process);
+     checkBlock is evaluated and loop is left, when false is
+     returned."
+
+    "set previousGroup to the main (non-modal) group"
 
-    myProcess := aProcess
-
-    "Modified: 3.9.1995 / 14:25:38 / claus"
+    previousGroup := WindowGroup activeGroup.
+    isModal := true.
+    self realizeTopViews:false.
+    self 
+	eventLoopWhile:checkBlock 
+	onLeave:[
+	    "
+	     cleanup, in case of a terminate
+	    "
+	    previousGroup := nil.
+	    topViews := nil.
+	    views := nil.
+	    "
+	     the following is rubbish;
+	     the views could be reused ..
+	    "
+"
+	    topViews notNil ifTrue:[
+		topViews do:[:aView |
+		    aView destroy
+		].
+		topViews := nil.
+	    ].
+	    views notNil ifTrue:[
+		views do:[:aView |
+		    aView destroy
+		].
+		views := nil.
+	    ].
+"
+	]
 ! !
 
 !WindowGroup methodsFor:'enumerating'!
 
-allViewsDo:aBlock
-    "evaluate aBlock for all views & topviews in this group.
-     This works on a copy of the view collection, to allow for
-     destroy and other collection changing operations to be done."
-
-    topViews notNil ifTrue:[topViews copy do:aBlock].
-    views notNil ifTrue:[views copy do:aBlock]
-! 
-
 allTopViewsExcept:aView do:aBlock
     "evaluate aBlock for all topviews except aView in this group.
      This works on a copy of the view collection, to allow for
@@ -427,6 +524,29 @@
     ].
 !
 
+allViewsDo:aBlock
+    "evaluate aBlock for all views & topviews in this group.
+     This works on a copy of the view collection, to allow for
+     destroy and other collection changing operations to be done."
+
+    topViews notNil ifTrue:[topViews copy do:aBlock].
+    views notNil ifTrue:[views copy do:aBlock]
+!
+
+partnersDo:aBlock
+    "evaluate aBlock for all partnerViews.
+     This works on a copy of the view collection, to allow for
+     destroy and other collection changing operations to be done."
+
+    topViews notNil ifTrue:[
+	topViews copy do:[:v |
+	    v notNil ifTrue:[
+		v type == #partner ifTrue:[aBlock value:v].
+	    ]
+	]
+    ].
+!
+
 slavesDo:aBlock
     "evaluate aBlock for all slaveViews.
      This works on a copy of the view collection, to allow for
@@ -439,75 +559,102 @@
 	    ]
 	]
     ].
-!
-
-partnersDo:aBlock
-    "evaluate aBlock for all partnerViews.
-     This works on a copy of the view collection, to allow for
-     destroy and other collection changing operations to be done."
-
-    topViews notNil ifTrue:[
-	topViews copy do:[:v |
-	    v notNil ifTrue:[
-		v type == #partner ifTrue:[aBlock value:v].
-	    ]
-	]
-    ].
-! !
-
-!WindowGroup methodsFor:'special'!
-
-showCursor:aCursor
-    "change the cursor to aCursor in all of my views."
-
-    |c|
-
-    c := aCursor.
-    self allViewsDo:[:aView |  
-	c := c on:(aView device).
-	aView device setCursor:c id in:aView id.
-    ].
-!
-
-restoreCursors
-    "restore the original cursors in all of my views"
-
-    |c|
-
-    self allViewsDo:[:aView |  
-	c := aView cursor on:(aView device).
-	aView device setCursor:(c id) in:(aView id).
-    ].
-!
-
-withCursor:aCursor do:aBlock
-    "evaluate aBlock while showing aCursor in all
-     my views (used to show wait-cursor while doing something).
-     Return the result as returned by aBlock."
-
-    |oldCursors|
-
-    "
-     get mapping of view->cursor for all of my subviews
-    "
-    oldCursors := IdentityDictionary new.
-    self allViewsDo:[:aView |
-	oldCursors at:aView put:(aView cursor).
-	aView cursor:aCursor
-    ].
-
-    ^ aBlock valueNowOrOnUnwindDo:[
-	"
-	 restore cursors from the mapping
-	"
-	oldCursors keysAndValuesDo:[:view :cursor |
-	    view cursor:cursor
-	]
-    ]
 ! !
 
 !WindowGroup methodsFor:'event handling'!
 
+eventLoop
+    "loop executed by windowGroup process;
+     wait-for and process events forever"
+
+   self eventLoopWhile:[true] onLeave:[]
+!
+
+eventLoopWhile:aBlock onLeave:cleanupActions
+    "wait-for and process events. 
+     Stay in this loop while there are still any views to dispatch for,
+     and aBlock evaluates to true."
+
+    |thisProcess|
+
+    thisProcess := Processor activeProcess.
+
+    [
+	"/
+	"/ on leave, exit the event loop
+	"/
+	LeaveSignal handle:[:ex |
+	    ex return
+	] do:[
+	    |p g mainGroup|
+
+	    isModal ifTrue:[
+		mainGroup := self mainGroup.
+	    ].
+
+	    aBlock whileTrue:[ 
+		LastActiveGroup := self.
+		LastActiveProcess := thisProcess.
+
+		(views isNil and:[topViews isNil]) ifTrue:[
+		    myProcess notNil ifTrue:[
+			p := myProcess.
+			myProcess := nil.
+			p terminate.
+			"not reached - there is no life after death"
+		    ].
+		    "
+		     this is the end of a modal loop
+		     (not having a private process ...)
+		    "
+		    ^ self
+		].
+
+		"/
+		"/ on abort, stay in the event loop
+		"/
+		AbortSignal handle:[:ex |
+		    ex return
+		] do:[
+		    "
+		     if modal, break out of the wait after some time
+		     to allow servicing update-events of the blocked
+		     windowgroup.
+		    "
+		    thisProcess setStateTo:#eventWait if:#active.
+		    isModal ifTrue:[
+			mySensor eventSemaphore waitWithTimeout:0.2.
+		    ] ifFalse:[
+			mySensor eventSemaphore wait.
+		    ].
+		    LastActiveGroup := self.
+		    LastActiveProcess := thisProcess.
+		    self processEvents.
+		].
+
+		"
+		 if modal, also check for redraw events in my maingroup
+		 (we arrive here after every event for myself or after the
+		  above timeout)
+		"
+		mainGroup notNil ifTrue:[
+		    mainGroup processExposeEvents.
+		]
+	    ].
+	].
+    ] valueNowOrOnUnwindDo:[
+	cleanupActions notNil ifTrue:[cleanupActions value]
+    ]
+!
+
+leaveEventLoop
+    "immediately leave the event loop, returning way back.
+     This can be used to leave (and closedown) a modal group.
+     (for normal views, this does not make sense)"
+
+    ^ LeaveSignal raise
+!
+
 processEvents
     "process events from either the damage- or user input queues.
      Abort is assumed to be handled elsewhere."
@@ -620,90 +767,6 @@
     ]
 !
 
-eventLoop
-    "loop executed by windowGroup process;
-     wait-for and process events forever"
-
-   self eventLoopWhile:[true] onLeave:[]
-!
-
-eventLoopWhile:aBlock onLeave:cleanupActions
-    "wait-for and process events. 
-     Stay in this loop while there are still any views to dispatch for,
-     and aBlock evaluates to true."
-
-    |thisProcess|
-
-    thisProcess := Processor activeProcess.
-
-    [
-	"/
-	"/ on leave, exit the event loop
-	"/
-	LeaveSignal handle:[:ex |
-	    ex return
-	] do:[
-	    |p g mainGroup|
-
-	    isModal ifTrue:[
-		mainGroup := self mainGroup.
-	    ].
-
-	    aBlock whileTrue:[ 
-		LastActiveGroup := self.
-		LastActiveProcess := thisProcess.
-
-		(views isNil and:[topViews isNil]) ifTrue:[
-		    myProcess notNil ifTrue:[
-			p := myProcess.
-			myProcess := nil.
-			p terminate.
-			"not reached - there is no life after death"
-		    ].
-		    "
-		     this is the end of a modal loop
-		     (not having a private process ...)
-		    "
-		    ^ self
-		].
-
-		"/
-		"/ on abort, stay in the event loop
-		"/
-		AbortSignal handle:[:ex |
-		    ex return
-		] do:[
-		    "
-		     if modal, break out of the wait after some time
-		     to allow servicing update-events of the blocked
-		     windowgroup.
-		    "
-		    thisProcess setStateTo:#eventWait if:#active.
-		    isModal ifTrue:[
-			mySensor eventSemaphore waitWithTimeout:0.2.
-		    ] ifFalse:[
-			mySensor eventSemaphore wait.
-		    ].
-		    LastActiveGroup := self.
-		    LastActiveProcess := thisProcess.
-		    self processEvents.
-		].
-
-		"
-		 if modal, also check for redraw events in my maingroup
-		 (we arrive here after every event for myself or after the
-		  above timeout)
-		"
-		mainGroup notNil ifTrue:[
-		    mainGroup processExposeEvents.
-		]
-	    ].
-	].
-    ] valueNowOrOnUnwindDo:[
-	cleanupActions notNil ifTrue:[cleanupActions value]
-    ]
-!
-
 waitForExposeFor:aView
     "wait for a noExpose on aView, then process all exposes.
      To be used after a scroll"
@@ -712,182 +775,53 @@
     AbortSignal catch:[
 	self processExposeEvents
     ]
-!
-
-leaveEventLoop
-    "immediately leave the event loop, returning way back.
-     This can be used to leave (and closedown) a modal group.
-     (for normal views, this does not make sense)"
-
-    ^ LeaveSignal raise
-! !
-
-!WindowGroup methodsFor:'activation / deactivation'!
-
-realizeTopViews:isRestart
-    "realize all topViews associated to this windowGroup.
-     If this is a restart, tell topViews about it."
-
-    topViews notNil ifTrue:[
-	topViews do:[:aView |
-	    aView realize.
-	    isRestart ifTrue:[
-		aView restarted
-	    ]
-	].
-    ].
-!
-
-restart
-    "restart after a snapin."
-
-    topViews notNil ifTrue:[
-	"
-	 need a new semaphore, since obsolete processes 
-	 (from our previous live) may still sit on the current semaphore
-	"
-	mySensor eventSemaphore:Semaphore new.
-	isModal ifFalse:[
-	    self startup:true 
-	]
-    ]
-!
-
-startup:isRestart
-    "startup the window-group;
-     this creates a new window group process, which
-     does the event processing."
-
-    |top nm dev devNm|
-
-    previousGroup := nil.
-    myProcess isNil ifTrue:[
-	isModal := false.
-	myProcess := [
-	    self realizeTopViews:isRestart.
-	    self eventLoopWhile:[true] onLeave:[]
-	] forkAt:Processor userSchedulingPriority.
-
-	(topViews notNil and:[topViews isEmpty not]) ifTrue:[
-	    "
-	     give the handler process a user friendly name
-	    "
-	    top := topViews first.
-	    nm := top processName.
-	    (dev := top device) notNil ifTrue:[
-		devNm := dev displayName.
-		(devNm notNil and:[devNm ~= Display displayName]) ifTrue:[
-		    nm := nm , ' (' , devNm , ')'
-		]
-	    ]
-	] ifFalse:[
-	    nm := 'window handler'.
-	].
-	myProcess name:nm.
-
-	"when the process dies, we have to close-down
-	 the views as well
-	"
-	myProcess exitAction:[self closeDownViews]
-    ]
-!
-
-startupModal:checkBlock
-    "startup the window-group in a modal loop (i.e. under the
-     currently running process);
-     checkBlock is evaluated and loop is left, when false is
-     returned."
-
-    "set previousGroup to the main (non-modal) group"
-
-    previousGroup := WindowGroup activeGroup.
-    isModal := true.
-    self realizeTopViews:false.
-    self 
-	eventLoopWhile:checkBlock 
-	onLeave:[
-	    "
-	     cleanup, in case of a terminate
-	    "
-	    previousGroup := nil.
-	    topViews := nil.
-	    views := nil.
-	    "
-	     the following is rubbish;
-	     the views could be reused ..
-	    "
-"
-	    topViews notNil ifTrue:[
-		topViews do:[:aView |
-		    aView destroy
-		].
-		topViews := nil.
-	    ].
-	    views notNil ifTrue:[
-		views do:[:aView |
-		    aView destroy
-		].
-		views := nil.
-	    ].
-"
-	]
-!
-
-closeDownViews
-    "destroy all views associated to this window group"
-
-    topViews notNil ifTrue:[
-	topViews do:[:aTopView | aTopView destroy]
-    ].
-    views := nil.
-    topViews := nil.
-    mySensor := nil.
-!
-
-shutdown
-    "shutdow the window group; close all views and
-     terminate process"
-
-    |p|
-
-    self closeDownViews.
-    myProcess notNil ifTrue:[
-	p := myProcess.
-	myProcess := nil.
-	p terminate.
-    ]
-! !
-
-!WindowGroup methodsFor:'initialization'!
-
-reinitialize
-    "reinitialize the windowgroup after an image restart"
-
-    "throw away old (zombie) process"
-    myProcess notNil ifTrue:[
-	"careful: the old processes exitaction must be cleared
-	 otherwise, it might do destroy or other actions when it
-	 gets finalized ...
-	"
-	myProcess exitAction:nil.
-	myProcess := nil.
-    ].
-
-    "throw away old events"
-    mySensor reinitialize
-!
-
-initialize
-    "setup the windowgroup, by creating a new sensor
-     and an event semaphore"
-
-    mySensor := WindowSensor new.
-    mySensor eventSemaphore:Semaphore new.
-    isModal := false.
 ! !
 
 !WindowGroup methodsFor:'focus control'!
 
+focusNext
+    "give focus to next view in focusSequence"
+
+    |index|
+
+    focusSequence size == 0 ifTrue:[^ self].
+    focusView notNil ifTrue:[
+	index := (focusSequence indexOf:focusView) + 1.
+	index > focusSequence size ifTrue:[index := 1].
+    ] ifFalse:[
+	index := 1.
+    ].
+    self focusView:(focusSequence at:index)
+
+    "
+     |top v1 v2|
+
+     top := StandardSystemView new.
+     v1 := EditTextView origin:0.0@0.0 corner:1.0@0.5 in:top.
+     v2 := EditTextView origin:0.0@0.5 corner:1.0@1.0 in:top.
+     top open.
+     top windowGroup focusSequence:(Array with:v1 with:v2).
+     top windowGroup focusOn:v1.
+     (Delay forSeconds:10) wait.
+     top windowGroup focusNext.
+    "
+!
+
+focusPrevious
+    "give focus to previous view in focusSequence"
+
+    |index|
+
+    focusSequence size == 0 ifTrue:[^ self].
+    focusView notNil ifTrue:[
+	index := (focusSequence indexOf:focusView) - 1.
+	index < 1 ifTrue:[index := focusSequence size].
+    ] ifFalse:[
+	index := focusSequence size.
+    ].
+    self focusView:(focusSequence at:index)
+!
+
 focusSequence
     "return the focus sequence for focusNext/focusPrevious.
      Focus is stepped in the order in which subviews occur in
@@ -930,49 +864,34 @@
      top open.
      top windowGroup focusView:v1.
     "
+! !
+
+!WindowGroup methodsFor:'initialization'!
+
+initialize
+    "setup the windowgroup, by creating a new sensor
+     and an event semaphore"
+
+    mySensor := WindowSensor new.
+    mySensor eventSemaphore:Semaphore new.
+    isModal := false.
 !
 
-focusNext
-    "give focus to next view in focusSequence"
-
-    |index|
-
-    focusSequence size == 0 ifTrue:[^ self].
-    focusView notNil ifTrue:[
-	index := (focusSequence indexOf:focusView) + 1.
-	index > focusSequence size ifTrue:[index := 1].
-    ] ifFalse:[
-	index := 1.
-    ].
-    self focusView:(focusSequence at:index)
-
-    "
-     |top v1 v2|
+reinitialize
+    "reinitialize the windowgroup after an image restart"
 
-     top := StandardSystemView new.
-     v1 := EditTextView origin:0.0@0.0 corner:1.0@0.5 in:top.
-     v2 := EditTextView origin:0.0@0.5 corner:1.0@1.0 in:top.
-     top open.
-     top windowGroup focusSequence:(Array with:v1 with:v2).
-     top windowGroup focusOn:v1.
-     (Delay forSeconds:10) wait.
-     top windowGroup focusNext.
-    "
-!
+    "throw away old (zombie) process"
+    myProcess notNil ifTrue:[
+	"careful: the old processes exitaction must be cleared
+	 otherwise, it might do destroy or other actions when it
+	 gets finalized ...
+	"
+	myProcess exitAction:nil.
+	myProcess := nil.
+    ].
 
-focusPrevious
-    "give focus to previous view in focusSequence"
-
-    |index|
-
-    focusSequence size == 0 ifTrue:[^ self].
-    focusView notNil ifTrue:[
-	index := (focusSequence indexOf:focusView) - 1.
-	index < 1 ifTrue:[index := focusSequence size].
-    ] ifFalse:[
-	index := focusSequence size.
-    ].
-    self focusView:(focusSequence at:index)
+    "throw away old events"
+    mySensor reinitialize
 ! !
 
 !WindowGroup methodsFor:'printing'!
@@ -990,3 +909,86 @@
     ].
     aStream nextPutAll:('WindowGroup(' , myProcess nameOrId , ')')
 ! !
+
+!WindowGroup methodsFor:'special'!
+
+restoreCursors
+    "restore the original cursors in all of my views"
+
+    |c|
+
+    self allViewsDo:[:aView |  
+	c := aView cursor on:(aView device).
+	aView device setCursor:(c id) in:(aView id).
+    ].
+!
+
+showCursor:aCursor
+    "change the cursor to aCursor in all of my views."
+
+    |c|
+
+    c := aCursor.
+    self allViewsDo:[:aView |  
+	c := c on:(aView device).
+	aView device setCursor:c id in:aView id.
+    ].
+!
+
+withCursor:aCursor do:aBlock
+    "evaluate aBlock while showing aCursor in all
+     my views (used to show wait-cursor while doing something).
+     Return the result as returned by aBlock."
+
+    |oldCursors|
+
+    "
+     get mapping of view->cursor for all of my subviews
+    "
+    oldCursors := IdentityDictionary new.
+    self allViewsDo:[:aView |
+	oldCursors at:aView put:(aView cursor).
+	aView cursor:aCursor
+    ].
+
+    ^ aBlock valueNowOrOnUnwindDo:[
+	"
+	 restore cursors from the mapping
+	"
+	oldCursors keysAndValuesDo:[:view :cursor |
+	    view cursor:cursor
+	]
+    ]
+! !
+
+!WindowGroup methodsFor:'special accessing'!
+
+setModal:aBoolean
+    "special entry for debugger: set the modal flag.
+     Not for public use"
+
+    isModal := aBoolean
+
+    "Modified: 3.9.1995 / 14:51:04 / claus"
+!
+
+setPreviousGroup:aGroup
+    "special entry for debugger:
+     set the windowgroup that started this group (for modal groups only).
+     This is not a public interface."
+
+    previousGroup := aGroup
+
+    "Modified: 3.9.1995 / 14:55:40 / claus"
+!
+
+setProcess:aProcess 
+    "special entry for debugger: set the windowGroups process.
+     Not for public use."
+
+    myProcess := aProcess
+
+    "Modified: 3.9.1995 / 14:25:38 / claus"
+! !
+
+WindowGroup initialize!