[Linux/X11][vw7.3][BUG] - InputState>>grabInputFor:

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

[Linux/X11][vw7.3][BUG] - InputState>>grabInputFor:

Ladislav Lenart
Hi,

I recently wanted to use InputState>>grabInputFor: to prevent user from
interacting with our application via other windows. I tried the
following example in Notice class>>showProgress:complete:while:title:
which uses #grabInputFor: method:

    Notice
        showProgress: 'In Progress'
        complete: 100000
        while: [100000 timesRepeat: [IncrementNotification raiseSignal]]
        title: 'Testing'"

When I execute it, the notice window appears on the screen and I can see
the progress growing. When the block is completed, the notice window is
closed, but whole X server goes bye-bye consuming 93% of CPU and the
only thing I can do is switch to text console, login and kill the X
server process. This continues to happen each time I try the example.
However exactly the same example works fine on Windows (verified).

Any ideas on where's the catch?

Thanks,

Ladislav Lenart

Reply | Threaded
Open this post in threaded view
|

Re: [Linux/X11][vw7.3][BUG] - InputState>>grabInputFor:

Reinout Heeck-2
This is a known problem and I reported it to Cincom several years ago.

The X server dutifully handles the 100000 requests to bring the window
to the front and change the window title by queuing them all up and
applying them one-by-one. I guess this huge queue bypasses some
optimization in the X server.

If you wait a couple of hours(!) the X server will unlock.


Anyway, you will *not* want to use this notifier on X because it will
prevent you from using apps on other desktops (if you switch desktop the
notifier will follow as if it is marked 'sticky' and it will *stay on top*).

Over time several Unix users have complained about this 'feature' of the
progress notifier and it's abuse in Store, but Cincom has not taken
action so far.

You can search Travis' blog, he has published some package to divert
progress notifier calls as messages in the Transcript.


Personally I just snub these methods on Notifier, replacing them with
  Cursor wait showWhile: ...



Bottom line: don't use Notice on X Windows :-(

R
-


Ladislav Lenart wrote:

> Hi,
>
> I recently wanted to use InputState>>grabInputFor: to prevent user from
> interacting with our application via other windows. I tried the
> following example in Notice class>>showProgress:complete:while:title:
> which uses #grabInputFor: method:
>
>    Notice
>        showProgress: 'In Progress'
>        complete: 100000
>        while: [100000 timesRepeat: [IncrementNotification raiseSignal]]
>        title: 'Testing'"
>
> When I execute it, the notice window appears on the screen and I can see
> the progress growing. When the block is completed, the notice window is
> closed, but whole X server goes bye-bye consuming 93% of CPU and the
> only thing I can do is switch to text console, login and kill the X
> server process. This continues to happen each time I try the example.
> However exactly the same example works fine on Windows (verified).
>
> Any ideas on where's the catch?
>
> Thanks,
>
> Ladislav Lenart
>
>


--
Reinout Heeck
-------------
Idle curiosity is the enemy of a quiet life.

Reply | Threaded
Open this post in threaded view
|

Re: [Linux/X11][vw7.3][BUG] - InputState>>grabInputFor:

Ladislav Lenart
Reinout Heeck wrote:

> This is a known problem and I reported it to Cincom several years ago.
>
> The X server dutifully handles the 100000 requests to bring the window
> to the front and change the window title by queuing them all up and
> applying them one-by-one. I guess this huge queue bypasses some
> optimization in the X server.
>
> If you wait a couple of hours(!) the X server will unlock.
>
>
> Anyway, you will *not* want to use this notifier on X because it will
> prevent you from using apps on other desktops (if you switch desktop
> the notifier will follow as if it is marked 'sticky' and it will *stay
> on top*).
>
> Over time several Unix users have complained about this 'feature' of
> the progress notifier and it's abuse in Store, but Cincom has not
> taken action so far.
>
> You can search Travis' blog, he has published some package to divert
> progress notifier calls as messages in the Transcript.
>
>
> Personally I just snub these methods on Notifier, replacing them with
>  Cursor wait showWhile: ...
>
>
>
> Bottom line: don't use Notice on X Windows :-(
>
> R
> -

Well, that explains a lot, although I don't like much what I read... :-(

Thank you anyway.

One last question: Is there any *working and portable* alternative for
achieving this particular behavior, that is to prevent user from
interacting with other parts of the application except for its one
concrete window while not affecting other running applications?

Ladislav Lenart

> Ladislav Lenart wrote:
>
>> Hi,
>>
>> I recently wanted to use InputState>>grabInputFor: to prevent user
>> from interacting with our application via other windows. I tried the
>> following example in Notice class>>showProgress:complete:while:title:
>> which uses #grabInputFor: method:
>>
>>    Notice
>>        showProgress: 'In Progress'
>>        complete: 100000
>>        while: [100000 timesRepeat: [IncrementNotification raiseSignal]]
>>        title: 'Testing'"
>>
>> When I execute it, the notice window appears on the screen and I can
>> see the progress growing. When the block is completed, the notice
>> window is closed, but whole X server goes bye-bye consuming 93% of
>> CPU and the only thing I can do is switch to text console, login and
>> kill the X server process. This continues to happen each time I try
>> the example. However exactly the same example works fine on Windows
>> (verified).
>>
>> Any ideas on where's the catch?
>>
>> Thanks,
>>
>> Ladislav Lenart
>

Reply | Threaded
Open this post in threaded view
|

RE: [Linux/X11][vw7.3][BUG] - InputState>>grabInputFor:

Steven Kelly
In reply to this post by Ladislav Lenart
From: Ladislav Lenart [mailto:[hidden email]]
> One last question: Is there any *working and portable* alternative for
> achieving this particular behavior, that is to prevent user from
> interacting with other parts of the application except for its one
> concrete window while not affecting other running applications?

There are several pieces of work in this direction, each with their own
set of requirements:

Steven Kelly, (RefreshingDisplayPolicy, 2002-2006 in public Store)
Terry Raymond (vwnc 2005-12-2, includes fileIn)
Bruce Badger (vwnc 2006-2-17, unpublished?)
Mark Pirogovsky (vwnc 2006-2-15, uses Notice (bad on Unix))

So far there is no superset or officially sanctioned version, but the
more optimistic among you may like to read something into the fact that
Sames asked myself and one or two others to submit their solutions to
him. The more pessimistic among us may like to read something into the
fact that I didn't get a reply from Sames when I sent him the code :-).

My package, RefreshingDisplayPolicy, is in the public repository. The
best documentation for it is to run "RefreshingDisplayPolicy example1".
Searching for RefreshingDisplayPolicy on the vwnc archive will turn up
the several earlier conversations about this topic, along with others'
solutions:

www.parcplace.net/list-search/vwnc-archive?query=RefreshingDisplayPolicy

Steve

Reply | Threaded
Open this post in threaded view
|

Re: [Linux/X11][vw7.3][BUG] - InputState>>grabInputFor:

Ladislav Lenart
Steven Kelly wrote:
From: Ladislav Lenart [[hidden email]]
  
One last question: Is there any *working and portable* alternative for
achieving this particular behavior, that is to prevent user from
interacting with other parts of the application except for its one
concrete window while not affecting other running applications?
    

There are several pieces of work in this direction, each with their own
set of requirements:

Steven Kelly, (RefreshingDisplayPolicy, 2002-2006 in public Store)
Terry Raymond (vwnc 2005-12-2, includes fileIn)
Bruce Badger (vwnc 2006-2-17, unpublished?)
Mark Pirogovsky (vwnc 2006-2-15, uses Notice (bad on Unix))

So far there is no superset or officially sanctioned version, but the
more optimistic among you may like to read something into the fact that
Sames asked myself and one or two others to submit their solutions to
him. The more pessimistic among us may like to read something into the
fact that I didn't get a reply from Sames when I sent him the code :-). 

My package, RefreshingDisplayPolicy, is in the public repository. The
best documentation for it is to run "RefreshingDisplayPolicy example1".
Searching for RefreshingDisplayPolicy on the vwnc archive will turn up
the several earlier conversations about this topic, along with others'
solutions:

www.parcplace.net/list-search/vwnc-archive?query=RefreshingDisplayPolicy

Steve
  
Thanks,

I have just loaded RefreshingDisplayPolicy to my image, but I am afraid that it is not exactly what I need, although it is definitely worth because I will also need to get rid of ugly grey areas while the application is busy...

<snippet from the package comment>
Call 'RefreshingDisplayPolicy usePixmapWhile: aBlock' for long operations, like you might call 'Cursor execute showWhile: aBlock'. Note that aBlock *may not* open dialogs, or *expect any other user input*, as all clicks and keypresses will be discarded during aBlock.
</snippet>

But what I would like to have now is this: During 'a simulation', user can not interact with all windows of my application except for one (the window where the simulation is currently running). In this window, he can do two actions:
1) He can click on particular toolbar button to pause the simulation (forked block).
2) He can close the window (with equivalent effect).
Once he does one of the two actions, he can interact with complete application again.

Am I right that your RefreshingDisplayPolicy can't do this for me?

Ladislav Lenart

Reply | Threaded
Open this post in threaded view
|

RE: [Linux/X11][vw7.3][BUG] - InputState>>grabInputFor:

Steven Kelly
In reply to this post by Ladislav Lenart

I have just loaded RefreshingDisplayPolicy to my image, but I am afraid that it is not exactly what I need, although it is definitely worth because I will also need to get rid of ugly grey areas while the application is busy...

<snippet from the package comment>
Call 'RefreshingDisplayPolicy usePixmapWhile: aBlock' for long operations, like you might call 'Cursor execute showWhile: aBlock'. Note that aBlock *may not* open dialogs, or *expect any other user input*, as all clicks and keypresses will be discarded during aBlock.
</snippet>

That comment should probably be updated to include the other way detailed in #example1. The other way opens a dialog progress window during the long block.

 

But what I would like to have now is this: During 'a simulation', user can not interact with all windows of my application except for one (the window where the simulation is currently running). In this window, he can do two actions:
1) He can click on particular toolbar button to pause the simulation (forked block).
2) He can close the window (with equivalent effect).
Once he does one of the two actions, he can interact with complete application again.

Am I right that your RefreshingDisplayPolicy can't do this for me?

I’m sure you could extend it to do this. Currently it adds all initially opened windows to DisabledWindows when it starts, and you’d presumably want to take your window out of that list. You might also look at how the ProgressDialogClass is used in ApplicationDialogController, although that’s probably not directly relevant if your window isn’t a dialog.

 

Implementing the ability to ignore all but one toolbar button will require a fair amount of code in your own window, regardless of which framework you use (unless you add horrible hacks to the framework to recognize that one widget as special). I wonder whether that is the right way to go. An alternative would be to make a subclass of ProgressDialog, containing Pause and “Stop & Close” buttons. You then install your ProgressDialog subclass as the value of ProgressDialogClass. Those would achieve the two actions you want, and you could simply use refresh:while:, without having to mess with DisabledWindows. As a UI, it’s probably not quite as nice as what you suggested, but it should work like a dream and take very little work to implement. It’s also a kind of configurability RefreshingDisplayPolicy was designed for.

 

My experience is that using #usePixmapWhile: (which doesn’t require opening a progress dialog) isn’t as effective as #refresh:while:, because VW leaks events in various ways. I kept patching and patching those leaks until it hit me one day that a dialog already effectively stops the input events getting through to other windows, whilst allowing refreshes. Since showing a progress dialog or some sort of Pause/Cancel dialog during a long operation is polite anyway, I think that’s generally the way to go.

 

Steve

Reply | Threaded
Open this post in threaded view
|

Re: [Linux/X11][vw7.3][BUG] - InputState>>grabInputFor:

Ladislav Lenart
Steven Kelly wrote:

I have just loaded RefreshingDisplayPolicy to my image, but I am afraid that it is not exactly what I need, although it is definitely worth because I will also need to get rid of ugly grey areas while the application is busy...

<snippet from the package comment>
Call 'RefreshingDisplayPolicy usePixmapWhile: aBlock' for long operations, like you might call 'Cursor execute showWhile: aBlock'. Note that aBlock *may not* open dialogs, or *expect any other user input*, as all clicks and keypresses will be discarded during aBlock.
</snippet>

That comment should probably be updated to include the other way detailed in #example1. The other way opens a dialog progress window during the long block.

 

But what I would like to have now is this: During 'a simulation', user can not interact with all windows of my application except for one (the window where the simulation is currently running). In this window, he can do two actions:
1) He can click on particular toolbar button to pause the simulation (forked block).
2) He can close the window (with equivalent effect).
Once he does one of the two actions, he can interact with complete application again.

Am I right that your RefreshingDisplayPolicy can't do this for me?

I’m sure you could extend it to do this. Currently it adds all initially opened windows to DisabledWindows when it starts, and you’d presumably want to take your window out of that list. You might also look at how the ProgressDialogClass is used in ApplicationDialogController, although that’s probably not directly relevant if your window isn’t a dialog.

Wow, that's great! To be honest, I didn't expect it. BTW I tried the RefreshingDisplayPolicy class>>example1 and it works just fine. I will definitely use it.

 

Implementing the ability to ignore all but one toolbar button will require a fair amount of code in your own window, regardless of which framework you use (unless you add horrible hacks to the framework to recognize that one widget as special).

Well, it is really not that hard, because:
1) Toolbar is built from Menu and menu item has enable / disable state (and so has the toolbar item).
2) You can supply aValueModel / aBlockClosure / aMenu to the method that should deliver the toolbar menu.
Now if you supply aValueModel as the toolbar source, each time it is changed, the toolbar is updated and redisplayed.
(BTW exactly the same applies to the main menu bar.)

I wonder whether that is the right way to go. An alternative would be to make a subclass of ProgressDialog, containing Pause and “Stop & Close” buttons. You then install your ProgressDialog subclass as the value of ProgressDialogClass. Those would achieve the two actions you want, and you could simply use refresh:while:, without having to mess with DisabledWindows. As a UI, it’s probably not quite as nice as what you suggested, but it should work like a dream and take very little work to implement. It’s also a kind of configurability RefreshingDisplayPolicy was designed for.

 

My experience is that using #usePixmapWhile: (which doesn’t require opening a progress dialog) isn’t as effective as #refresh:while:, because VW leaks events in various ways. I kept patching and patching those leaks until it hit me one day that a dialog already effectively stops the input events getting through to other windows, whilst allowing refreshes. Since showing a progress dialog or some sort of Pause/Cancel dialog during a long operation is polite anyway, I think that’s generally the way to go.

Well, I will consider this. But unfortunately there is one tiny little detail and that is, that during the simulation, a dialog can be opened that asks user which way to continue (if there is a condition branch). I am not sure how would this behave - second dialog opened from the same parent window while the other one is still opened.

One way or the other, thank you VERY MUCH for your quick and apposite answers,

Ladislav Lenart

Reply | Threaded
Open this post in threaded view
|

RE: [Linux/X11][vw7.3][BUG] - InputState>>grabInputFor:

Steven Kelly
In reply to this post by Ladislav Lenart

But what I would like to have now is this: During 'a simulation', user can not interact with all windows of my application except for one (the window where the simulation is currently running). In this window, he can do two actions:
1) He can click on particular toolbar button to pause the simulation (forked block).
2) He can close the window (with equivalent effect).
Once he does one of the two actions, he can interact with complete application again.

Am I right that your RefreshingDisplayPolicy can't do this for me?

I’m sure you could extend it to do this. Currently it adds all initially opened windows to DisabledWindows when it starts, and you’d presumably want to take your window out of that list. You might also look at how the ProgressDialogClass is used in ApplicationDialogController, although that’s probably not directly relevant if your window isn’t a dialog.

 

Implementing the ability to ignore all but one toolbar button will require a fair amount of code in your own window, regardless of which framework you use (unless you add horrible hacks to the framework to recognize that one widget as special).

Well, it is really not that hard, because:
1) Toolbar is built from Menu and menu item has enable / disable state (and so has the toolbar item).
2) You can supply aValueModel / aBlockClosure / aMenu to the method that should deliver the toolbar menu.
Now if you supply aValueModel as the toolbar source, each time it is changed, the toolbar is updated and redisplayed.
(BTW exactly the same applies to the main menu bar.)

 

Yes, that’s what I was envisaging: use the enablement selector for the toolbar and menu items, and also for any widgets in the main body of the window (presuming you want them to remain visible but disabled). You’ll have to add the same disable option to rather a lot of components, but at least they can all point to the same method / ValueHolder.

 

I wonder whether that is the right way to go. An alternative would be to make a subclass of ProgressDialog, containing Pause and “Stop & Close” buttons. You then install your ProgressDialog subclass as the value of ProgressDialogClass. Those would achieve the two actions you want, and you could simply use refresh:while:, without having to mess with DisabledWindows. As a UI, it’s probably not quite as nice as what you suggested, but it should work like a dream and take very little work to implement. It’s also a kind of configurability RefreshingDisplayPolicy was designed for.

 

Well, I will consider this. But unfortunately there is one tiny little detail and that is, that during the simulation, a dialog can be opened that asks user which way to continue (if there is a condition branch). I am not sure how would this behave - second dialog opened from the same parent window while the other one is still opened.

It should “just work” (the package comment says not to do this, but things have improved since then). We open dialogs from code run in the block supplied, and I presume that’s just what is happening in your case. That’s the reason for the override in ApplicationDialogController. If you open new normal windows, I’m not so sure: I think then they will not be able to receive input events (because a dialog is open), but they will refresh. Hmm, just tried it (code below) and here are the results:

 

usePixmapWhile: Opening new dialogs works fine, opening new non-dialog windows works fine

refresh:while: Opening new dialogs works fine, opening new non-dialog windows leaves them unresponsive to input and refreshing during the long block, and they can be raised above the progress dialog, but they work fine after.

 

I’m not sure exactly why new non-dialog windows behave like that in refresh:while:, but it’s probably because they are not being opened in the main UI process, but in the priority 49 process that runs the block, and that is already spending all its time running the factorial operation. In other words, we’re back to the same situation as before RefreshingDisplayPolicy: windows don’t update, because they’re busy doing the long block. In this case, inserting Processor yield in the long block helps ensure at least some refreshing, although not particularly enthusiastically.

 

In any case, I wouldn’t advise opening new non-dialog windows from the long blocks: in both cases after the blocks they remain in their own WindowManager with a baseProcess at priority 49, which works OK generally but is a potential source of problems.

 

One way or the other, thank you VERY MUCH for your quick and apposite answers,

No problem at all – I’ve spent far more time earlier debating the issues and trying to persuade Cincom this is important. Even if now I’m only helping one person directly, it’s one more than I’ve been able to do so far :-).

 

Steve

Test code: replace Workspace open with Dialog warn: ‘foo’ or whatever to check dialogs

 

RefreshingDisplayPolicy usePixmapWhile:

  [100 timesRepeat: [4000 factorial].

  Workspace open.

  100 timesRepeat: [4000 factorial]].

 

RefreshingDisplayPolicy refresh: true while:

  [Transcript cr.

  1 to: 200 do: [:ix |

              4000 factorial.

              ProgressDialog progress value: ix/200.0.

              ix \\ 10 = 0 ifTrue: [Transcript print: ix; space].

              ix = 100 ifTrue: [Workspace open].

“Processor yield” “turn this on to get some refreshing when a normal window has been opened”]].

Reply | Threaded
Open this post in threaded view
|

[BUG] [Linux/X11][vw7.x] Notice examples are evil

Reinout Heeck-2
In reply to this post by Ladislav Lenart
So can this be AR-ed please?


The examples provided in the comments of

   Notice class>>showProgress:complete:while:
and
   notice class>>showProgress:complete:while:title:

will choke an X11 session (100% CPU for several hours).

My knee-jerk reaction was to suggest to remove them, but on second
thought it would be actually informative if a prominent warning is added
to these comments. Something along the lines of

"WARNING:
this example will hang your desktop if you are running on Unix/XWindows,
CLOSE ALL APPLICATIONS BEFORE RUNNING this example and save your image,
since you will probably need to kill your X session afterwards."


Seen on Linux/XFree/KDE, various versions of VW including 7.4


--
Reinout Heeck
-------------
Idle curiosity is the enemy of a quiet life.