[vw7.7] Bug in Dialog>>defaultParentWindow

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

[vw7.7] Bug in Dialog>>defaultParentWindow

Mark Plas

Hi,

 

I think there is a bug/problem in Dialog class>>defaultParentWindow which causes button presses to be executed multiple times in row instead of just once.

 

Here's what I do:

 

-          take a clean vw7.7 image

-          go to the method FileDialog>>requestNewDirectoryName and add a 2 seconds delay in it:

 

FileDialog>>requestNewDirectoryName

 

        | name |

        2 seconds wait.

        name := Dialog

                       request: #CreateDirectoryNamedC << #dialogs >> 'Create a directory named:'

                       initialAnswer: ''

                       onCancel: [^nil].

        ^self directory construct: name

 

 

-          Do this: "FileDialog chooseDirectoryExample" <doit>

 

If you now press the 'create a new directory' button it will wait 2 seconds before asking you the filename. During those 2 seconds you should click on the button again.

 

What happens then is that #requestNewDirectoryName will be executed twice. The reason for this lies in this method:

 

 

Dialog class>>defaultParentWindow

                "Answer a default window to use as the parent of a dialog."

 

                | window windowManager scheduledWindows |

                windowManager := Processor activeProcess windowManager.

                windowManager ifNotNil: [:manager| manager processOutstandingEvents].

                window := Window currentWindow.

                ((window isKindOf: ScheduledWindow) and: [window windowManager == windowManager])

                               ifTrue: [^window].

                (scheduledWindows := ScheduledWindow scheduledWindows) isEmpty

                               ifTrue: [^nil].

                ^scheduledWindows

                               detect: [:each | each windowManager == windowManager]

                               ifNone: [scheduledWindows first]

 

 

The #processOutstandingEvents method gets performed before the directory name dialog opens and causes the second click (and third, and fourth, …) on the button to be handled again by the button causing it to perform the same command again.

 

Below you find a stack trace in which you can see this. #createDirectory can be seen twice in the stack.

 

What is the reason for the #defaultParentWindow method to perform #processOutstandingEvents? Can it be safely removed?

 

How can I avoid this problem?

 

Thanks,

Mark

 

 

User Interrupt

Semaphore>>waitIfCurtailedSignal

EventQueue>>next

WindowManager>>processNextEvent

optimized [] in ApplicationDialogController>>eventLoop

BlockClosure>>ensure:

ApplicationDialogController>>eventLoop

ApplicationDialogController(ApplicationStandardSystemController)>>controlLoop

ApplicationDialogController(Controller)>>startUp

optimized [] in StandardSystemController>>startUp

BlockClosure>>on:do:

BlockClosure>>on:from:do:

ApplicationDialogController(StandardSystemController)>>startUp

optimized [] in [] in ApplicationDialogController>>openTransientViews

BlockClosure>>ensure:

optimized [] in ApplicationDialogController>>openTransientViews

Cursor>>showWhile:

ApplicationDialogController>>openTransientViews

ApplicationWindow(ScheduledWindow)>>openTransientIn:type:postOpen:

ApplicationWindow(ScheduledWindow)>>openTransientIn:type:

UIBuilder>>openPopUpIn:type:

UIBuilder>>openDialogWithExtent:

SimpleDialog>>request:initialAnswer:onCancel:windowLabel:for:

SimpleDialog>>request:initialAnswer:onCancel:for:

SimpleDialog>>request:initialAnswer:onCancel:

Dialog class>>request:initialAnswer:onCancel:

ChooseDirectoryDialog(FileDialog)>>requestNewDirectoryName

ChooseDirectoryDialog(FileDialog)>>createDirectory

ChooseDirectoryDialog>>createDirectory

optimized [] in ApplicationModel>>actionFor:

optimized [] in ActionButtonSpec>>typeConvert:

PluggableAdaptor>>setValue:

PluggableAdaptor(ValueModel)>>value:

WinXPTriggerButtonController(TriggerButtonController)>>pressAction

TriggerButtonTracker(BasicButtonTracker)>>finishSelectionFor:

TriggerButtonTracker>>finishSelectionFor:

TriggerButtonTracker(SelectionTracker)>>redButtonReleasedEvent:

RedButtonReleasedEvent>>dispatchTo:

TriggerButtonTracker(SelectionTracker)>>handleEvent:

EventDispatcher>>dispatch:to:

EventDispatcher>>dispatchEvent:

RedButtonReleasedEvent(Event)>>dispatch

RedButtonReleasedEvent(Event)>>dispatchForWindowManager:

optimized [] in WindowManager>>safelyDispatchForWindowManager:

BlockClosure>>on:do:

WindowManager>>safelyDispatchForWindowManager:

WindowManager>>processNextAvailableEvent

optimized [] in WindowManager>>processOutstandingEvents

BlockClosure>>ensure:

WindowManager>>processOutstandingEvents

optimized [] in Dialog class>>defaultParentWindow

BlockClosure>>cull:

WindowManager(Object)>>ifNotNil:

Dialog class>>defaultParentWindow

SimpleDialog>>initializeBuilderFor:

SimpleDialog>>request:initialAnswer:onCancel:windowLabel:for:

SimpleDialog>>request:initialAnswer:onCancel:for:

SimpleDialog>>request:initialAnswer:onCancel:

Dialog class>>request:initialAnswer:onCancel:

ChooseDirectoryDialog(FileDialog)>>requestNewDirectoryName

ChooseDirectoryDialog(FileDialog)>>createDirectory

ChooseDirectoryDialog>>createDirectory

optimized [] in ApplicationModel>>actionFor:

optimized [] in ActionButtonSpec>>typeConvert:

PluggableAdaptor>>setValue:

PluggableAdaptor(ValueModel)>>value:

WinXPTriggerButtonController(TriggerButtonController)>>pressAction

TriggerButtonTracker(BasicButtonTracker)>>finishSelectionFor:

TriggerButtonTracker>>finishSelectionFor:

TriggerButtonTracker(SelectionTracker)>>redButtonReleasedEvent:

RedButtonReleasedEvent>>dispatchTo:

TriggerButtonTracker(SelectionTracker)>>handleEvent:

EventDispatcher>>dispatch:to:

EventDispatcher>>dispatchEvent:

RedButtonReleasedEvent(Event)>>dispatch

RedButtonReleasedEvent(Event)>>dispatchForWindowManager:

optimized [] in WindowManager>>safelyDispatchForWindowManager:

BlockClosure>>on:do:

WindowManager>>safelyDispatchForWindowManager:

WindowManager>>processNextEvent

optimized [] in ApplicationDialogController>>eventLoop

BlockClosure>>ensure:

ApplicationDialogController>>eventLoop

ApplicationDialogController(ApplicationStandardSystemController)>>controlLoop

ApplicationDialogController(Controller)>>startUp

optimized [] in StandardSystemController>>startUp

BlockClosure>>on:do:

BlockClosure>>on:from:do:

ApplicationDialogController(StandardSystemController)>>startUp

optimized [] in [] in ApplicationDialogController>>openTransientViews

BlockClosure>>ensure:

optimized [] in ApplicationDialogController>>openTransientViews

BlockClosure>>ensure:

Cursor>>showWhile:

ApplicationDialogController>>openTransientViews

ApplicationWindow(ScheduledWindow)>>openTransientIn:type:postOpen:

ApplicationWindow(ScheduledWindow)>>openTransientIn:type:

UIBuilder>>openPopUpIn:type:

UIBuilder>>openDialog

ChooseDirectoryDialog(SimpleDialog)>>openFrom:

ChooseDirectoryDialog(SimpleDialog)>>openFor:interface:

ChooseDirectoryDialog(SimpleDialog)>>openInterface:

ChooseDirectoryDialog(ApplicationModel)>>openInterface

ChooseDirectoryDialog(ApplicationModel)>>open

FileDialog class>>chooseDirectoryExample

UndefinedObject>>unboundMethod

UndefinedObject(Object)>>performMethod:arguments:

UndefinedObject(Object)>>performMethod:

TextEditorController(ParagraphEditor)>>evaluateCompiled:

optimized [] in ParagraphEditor>>evaluateSelection

BlockClosure>>ensure:

Cursor>>showWhile:

TextEditorController(ParagraphEditor)>>evaluateSelection

optimized [] in ParagraphEditor>>doIt

BlockClosure>>on:do:

TextEditorController(ParagraphEditor)>>doIt

TextEditorController(ParagraphEditor)>>performCommand:

TextEditorController(ParagraphEditor)>>doItKey:

TextEditorController(ParagraphEditor)>>doItOrDisplayDateKey:

optimized [] in TextEditorController>>processKeyboardEvent:

DispatchTable>>add:do:

TextEditorController>>processKeyboardEvent:

TextEditorController(Controller)>>keyPressedEvent:

KeyPressedEvent>>dispatchTo:

TextEditorController(ControllerWithMenu)>>handleEvent:

[] in [] in KeyboardProcessor>>processKeyboardEvent:

BlockClosure>>cull:

TextEditorController(Object)>>ifNotNil:

[] in KeyboardProcessor>>processKeyboardEvent:

BlockClosure>>cull:

TextEditorController(Object)>>ifNotNil:

KeyboardProcessor>>processKeyboardEvent:

KeyboardProcessor>>processKeyboardEvent:for:

EventDispatcher>>dispatchEvent:

KeyPressedEvent(Event)>>dispatch

KeyPressedEvent(Event)>>dispatchForWindowManager:

optimized [] in WindowManager>>safelyDispatchForWindowManager:

BlockClosure>>on:do:

WindowManager>>safelyDispatchForWindowManager:

WindowManager>>processNextEvent

optimized [] in [] in WindowManager>>newProcess

BlockClosure>>on:do:

optimized [] in WindowManager>>newProcess

BlockClosure>>on:do:

optimized [] in Process class>>forBlock:priority:

 

 


_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: [vw7.7] Bug in Dialog>>defaultParentWindow

Holger Kleinsorgen-4

another example why this side effect is bad:

 

| win |

win := (ScheduledControllers scheduledControllers detect: [ : c | c model class = VisualLauncher ]) view.

[

                Dialog confirm: 'Ok 1' for: win

] uiEventFor: win.

[

                Dialog confirm: 'Ok 2' for: win

] uiEventFor: win.

 

Since # uiEventFor: evaluates the code within the window event loop, one would expect "OK 1" before "OK 2".

However, somewhere in the dialog code, #openDialogWithExtent: sends #defaultParentWindow, so the event processing is nested, and "OK 2" appears before "OK 1".

 

IMHO, no matter why process outstandingEvents is needed, it's a bug and should be eliminated soon.

 

Von: [hidden email] [mailto:[hidden email]] Im Auftrag von Mark Plas
Gesendet: Montag, 12. Juli 2010 10:01
An: vwnc NC
Betreff: [vwnc] [vw7.7] Bug in Dialog>>defaultParentWindow

 

Hi,

 

I think there is a bug/problem in Dialog class>>defaultParentWindow which causes button presses to be executed multiple times in row instead of just once.

 

Here's what I do:

 

-          take a clean vw7.7 image

-          go to the method FileDialog>>requestNewDirectoryName and add a 2 seconds delay in it:

 

FileDialog>>requestNewDirectoryName

 

        | name |

        2 seconds wait.

        name := Dialog

                       request: #CreateDirectoryNamedC << #dialogs >> 'Create a directory named:'

                       initialAnswer: ''

                       onCancel: [^nil].

        ^self directory construct: name

 

 

-          Do this: "FileDialog chooseDirectoryExample" <doit>

 

If you now press the 'create a new directory' button it will wait 2 seconds before asking you the filename. During those 2 seconds you should click on the button again.

 

What happens then is that #requestNewDirectoryName will be executed twice. The reason for this lies in this method:

 

 

Dialog class>>defaultParentWindow

                "Answer a default window to use as the parent of a dialog."

 

                | window windowManager scheduledWindows |

                windowManager := Processor activeProcess windowManager.

                windowManager ifNotNil: [:manager| manager processOutstandingEvents].

                window := Window currentWindow.

                ((window isKindOf: ScheduledWindow) and: [window windowManager == windowManager])

                               ifTrue: [^window].

                (scheduledWindows := ScheduledWindow scheduledWindows) isEmpty

                               ifTrue: [^nil].

                ^scheduledWindows

                               detect: [:each | each windowManager == windowManager]

                               ifNone: [scheduledWindows first]

 

 

The #processOutstandingEvents method gets performed before the directory name dialog opens and causes the second click (and third, and fourth, …) on the button to be handled again by the button causing it to perform the same command again.

 

Below you find a stack trace in which you can see this. #createDirectory can be seen twice in the stack.

 

What is the reason for the #defaultParentWindow method to perform #processOutstandingEvents? Can it be safely removed?

 

How can I avoid this problem?

 

Thanks,

Mark

 

 

User Interrupt

Semaphore>>waitIfCurtailedSignal

EventQueue>>next

WindowManager>>processNextEvent

optimized [] in ApplicationDialogController>>eventLoop

BlockClosure>>ensure:

ApplicationDialogController>>eventLoop

ApplicationDialogController(ApplicationStandardSystemController)>>controlLoop

ApplicationDialogController(Controller)>>startUp

optimized [] in StandardSystemController>>startUp

BlockClosure>>on:do:

BlockClosure>>on:from:do:

ApplicationDialogController(StandardSystemController)>>startUp

optimized [] in [] in ApplicationDialogController>>openTransientViews

BlockClosure>>ensure:

optimized [] in ApplicationDialogController>>openTransientViews

Cursor>>showWhile:

ApplicationDialogController>>openTransientViews

ApplicationWindow(ScheduledWindow)>>openTransientIn:type:postOpen:

ApplicationWindow(ScheduledWindow)>>openTransientIn:type:

UIBuilder>>openPopUpIn:type:

UIBuilder>>openDialogWithExtent:

SimpleDialog>>request:initialAnswer:onCancel:windowLabel:for:

SimpleDialog>>request:initialAnswer:onCancel:for:

SimpleDialog>>request:initialAnswer:onCancel:

Dialog class>>request:initialAnswer:onCancel:

ChooseDirectoryDialog(FileDialog)>>requestNewDirectoryName

ChooseDirectoryDialog(FileDialog)>>createDirectory

ChooseDirectoryDialog>>createDirectory

optimized [] in ApplicationModel>>actionFor:

optimized [] in ActionButtonSpec>>typeConvert:

PluggableAdaptor>>setValue:

PluggableAdaptor(ValueModel)>>value:

WinXPTriggerButtonController(TriggerButtonController)>>pressAction

TriggerButtonTracker(BasicButtonTracker)>>finishSelectionFor:

TriggerButtonTracker>>finishSelectionFor:

TriggerButtonTracker(SelectionTracker)>>redButtonReleasedEvent:

RedButtonReleasedEvent>>dispatchTo:

TriggerButtonTracker(SelectionTracker)>>handleEvent:

EventDispatcher>>dispatch:to:

EventDispatcher>>dispatchEvent:

RedButtonReleasedEvent(Event)>>dispatch

RedButtonReleasedEvent(Event)>>dispatchForWindowManager:

optimized [] in WindowManager>>safelyDispatchForWindowManager:

BlockClosure>>on:do:

WindowManager>>safelyDispatchForWindowManager:

WindowManager>>processNextAvailableEvent

optimized [] in WindowManager>>processOutstandingEvents

BlockClosure>>ensure:

WindowManager>>processOutstandingEvents

optimized [] in Dialog class>>defaultParentWindow

BlockClosure>>cull:

WindowManager(Object)>>ifNotNil:

Dialog class>>defaultParentWindow

SimpleDialog>>initializeBuilderFor:

SimpleDialog>>request:initialAnswer:onCancel:windowLabel:for:

SimpleDialog>>request:initialAnswer:onCancel:for:

SimpleDialog>>request:initialAnswer:onCancel:

Dialog class>>request:initialAnswer:onCancel:

ChooseDirectoryDialog(FileDialog)>>requestNewDirectoryName

ChooseDirectoryDialog(FileDialog)>>createDirectory

ChooseDirectoryDialog>>createDirectory

optimized [] in ApplicationModel>>actionFor:

optimized [] in ActionButtonSpec>>typeConvert:

PluggableAdaptor>>setValue:

PluggableAdaptor(ValueModel)>>value:

WinXPTriggerButtonController(TriggerButtonController)>>pressAction

TriggerButtonTracker(BasicButtonTracker)>>finishSelectionFor:

TriggerButtonTracker>>finishSelectionFor:

TriggerButtonTracker(SelectionTracker)>>redButtonReleasedEvent:

RedButtonReleasedEvent>>dispatchTo:

TriggerButtonTracker(SelectionTracker)>>handleEvent:

EventDispatcher>>dispatch:to:

EventDispatcher>>dispatchEvent:

RedButtonReleasedEvent(Event)>>dispatch

RedButtonReleasedEvent(Event)>>dispatchForWindowManager:

optimized [] in WindowManager>>safelyDispatchForWindowManager:

BlockClosure>>on:do:

WindowManager>>safelyDispatchForWindowManager:

WindowManager>>processNextEvent

optimized [] in ApplicationDialogController>>eventLoop

BlockClosure>>ensure:

ApplicationDialogController>>eventLoop

ApplicationDialogController(ApplicationStandardSystemController)>>controlLoop

ApplicationDialogController(Controller)>>startUp

optimized [] in StandardSystemController>>startUp

BlockClosure>>on:do:

BlockClosure>>on:from:do:

ApplicationDialogController(StandardSystemController)>>startUp

optimized [] in [] in ApplicationDialogController>>openTransientViews

BlockClosure>>ensure:

optimized [] in ApplicationDialogController>>openTransientViews

BlockClosure>>ensure:

Cursor>>showWhile:

ApplicationDialogController>>openTransientViews

ApplicationWindow(ScheduledWindow)>>openTransientIn:type:postOpen:

ApplicationWindow(ScheduledWindow)>>openTransientIn:type:

UIBuilder>>openPopUpIn:type:

UIBuilder>>openDialog

ChooseDirectoryDialog(SimpleDialog)>>openFrom:

ChooseDirectoryDialog(SimpleDialog)>>openFor:interface:

ChooseDirectoryDialog(SimpleDialog)>>openInterface:

ChooseDirectoryDialog(ApplicationModel)>>openInterface

ChooseDirectoryDialog(ApplicationModel)>>open

FileDialog class>>chooseDirectoryExample

UndefinedObject>>unboundMethod

UndefinedObject(Object)>>performMethod:arguments:

UndefinedObject(Object)>>performMethod:

TextEditorController(ParagraphEditor)>>evaluateCompiled:

optimized [] in ParagraphEditor>>evaluateSelection

BlockClosure>>ensure:

Cursor>>showWhile:

TextEditorController(ParagraphEditor)>>evaluateSelection

optimized [] in ParagraphEditor>>doIt

BlockClosure>>on:do:

TextEditorController(ParagraphEditor)>>doIt

TextEditorController(ParagraphEditor)>>performCommand:

TextEditorController(ParagraphEditor)>>doItKey:

TextEditorController(ParagraphEditor)>>doItOrDisplayDateKey:

optimized [] in TextEditorController>>processKeyboardEvent:

DispatchTable>>add:do:

TextEditorController>>processKeyboardEvent:

TextEditorController(Controller)>>keyPressedEvent:

KeyPressedEvent>>dispatchTo:

TextEditorController(ControllerWithMenu)>>handleEvent:

[] in [] in KeyboardProcessor>>processKeyboardEvent:

BlockClosure>>cull:

TextEditorController(Object)>>ifNotNil:

[] in KeyboardProcessor>>processKeyboardEvent:

BlockClosure>>cull:

TextEditorController(Object)>>ifNotNil:

KeyboardProcessor>>processKeyboardEvent:

KeyboardProcessor>>processKeyboardEvent:for:

EventDispatcher>>dispatchEvent:

KeyPressedEvent(Event)>>dispatch

KeyPressedEvent(Event)>>dispatchForWindowManager:

optimized [] in WindowManager>>safelyDispatchForWindowManager:

BlockClosure>>on:do:

WindowManager>>safelyDispatchForWindowManager:

WindowManager>>processNextEvent

optimized [] in [] in WindowManager>>newProcess

BlockClosure>>on:do:

optimized [] in WindowManager>>newProcess

BlockClosure>>on:do:

optimized [] in Process class>>forBlock:priority:

 

 


_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: [vw7.7] Bug in Dialog>>defaultParentWindow

Travis Griggs-3
In reply to this post by Mark Plas

On Jul 12, 2010, at 1:01 AM, Mark Plas wrote:

Hi,
 
I think there is a bug/problem in Dialog class>>defaultParentWindow which causes button presses to be executed multiple times in row instead of just once.
 
Here's what I do:
 
-          take a clean vw7.7 image
-          go to the method FileDialog>>requestNewDirectoryName and add a 2 seconds delay in it:
 
FileDialog>>requestNewDirectoryName
 
        | name |
        2 seconds wait.
        name := Dialog
                       request: #CreateDirectoryNamedC << #dialogs >> 'Create a directory named:'
                       initialAnswer: ''
                       onCancel: [^nil].
        ^self directory construct: name
 
 
-          Do this: "FileDialog chooseDirectoryExample" <doit>
 
If you now press the 'create a new directory' button it will wait 2 seconds before asking you the filename. During those 2 seconds you should click on the button again.
 
What happens then is that #requestNewDirectoryName will be executed twice. The reason for this lies in this method:
 
 
Dialog class>>defaultParentWindow
                "Answer a default window to use as the parent of a dialog."
 
                | window windowManager scheduledWindows |
                windowManager := Processor activeProcess windowManager.
                windowManager ifNotNil: [:manager| manager processOutstandingEvents].
                window := Window currentWindow.
                ((window isKindOf: ScheduledWindow) and: [window windowManager == windowManager])
                               ifTrue: [^window].
                (scheduledWindows := ScheduledWindow scheduledWindows) isEmpty
                               ifTrue: [^nil].
                ^scheduledWindows
                               detect: [:each | each windowManager == windowManager]
                               ifNone: [scheduledWindows first]
 
 
The #processOutstandingEvents method gets performed before the directory name dialog opens and causes the second click (and third, and fourth, …) on the button to be handled again by the button causing it to perform the same command again.
 
Below you find a stack trace in which you can see this. #createDirectory can be seen twice in the stack.
 
What is the reason for the #defaultParentWindow method to perform #processOutstandingEvents? Can it be safely removed?
 
How can I avoid this problem?
 
Thanks,
Mark

A reason it might be there, is to allow any window updates to be processed. For example, the event queue may have information in that updates the status of windows (such as closing them, or opening new ones, or resizing, etc).

--
Travis Griggs
Objologist
"I think that we should be men first, and subjects afterward." - Henry David Thoreau




_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc