eserte / perl-tk

the perl module Tk
https://metacpan.org/release/Tk
Other
44 stars 31 forks source link

Tk::ErrorDialog collision breaks 'OK' button #2

Closed mcast closed 10 years ago

mcast commented 11 years ago

(sorry, premature key)

I noticed that a second call to Tk::Error while the errordialog is open would brick our application. This test demonstrates the problem, but I have not yet fixed it.

I'm intending to replace the Tk::ErrorDialog with something local, sorry. I think we need a multi-error window... because we have lots of errors(!).

mcast commented 11 years ago

/me wonders where the preview button is for pull requests. Pressed Enter in the subject and submitted it accidentally before proofing; then the sequence <Enter> is hidden in the markup view, but one Edit is enough.

eserte commented 11 years ago

Confirmed. A simpler script to demonstrate the problem looks like this:

use Tk;
use Tk::ErrorDialog;
my $mw = tkinit;
$mw->after(100, sub { die 1 });
$mw->after(300, sub { die 2 });
MainLoop;

A user can workaround the problem by trying a X11 operation which sends some event to the dialog (for example a Configure event), e.g. obscuring the dialog box by moving another window over it. After this, the OK button is again functional.

I suspect the problem happens because multiple waitVariable calls are stacked in an unfortunate way in Tk::DialogBox. Maybe a solution is to add code to the Tk::Error subroutine and detect that the dialog is already active. In this case, the ->Show() method shouldn't be called again. Only the dialog text could be changed, and the trace window updated.

Another possible solution could be to not re-use the error dialog for multiple errors. But this could result in a cluttered display if many errors happen at the same time.

Regards, Slaven

mcast commented 11 years ago

On Tue, Aug 20, 2013 at 01:22:17AM -0700, Slaven Rezić wrote:

Confirmed. A simpler script to demonstrate the problem looks like this:

use Tk;
use Tk::ErrorDialog;
my $mw = tkinit;
$mw->after(100, sub { die 1 });
$mw->after(300, sub { die 2 });
MainLoop;

Yes, that is the same problem.

A user can workaround the problem by trying a X11 operation which sends some event to the dialog (for example a Configure event), e.g. obscuring the dialog box by moving another window over it. After this, the OK button is again functional.

Merely obscuring the dialog box isn't a workaround for the version (window manager?) I have, but minimising its parent window and restoring is. Also switching virtual desktops will rescue it.

Thanks for noticing this.

We stopped using it[1] recently, so I'm afraid my interest in the bug is fading.

I suspect the problem happens because multiple waitVariable calls are stacked in an unfortunate way in Tk::DialogBox.

We have had some serious problems with tangled (as I called them) waitVariables, piling up some seriously large stacktraces and leaving code execution pending where it should have happened promptly.

Since realising the problem, we are moving to more callbacks, away from trying to create the illusion of a synchronous call.

There may be a critical time- or SLOC-density of wait* calls[2], beyond which reasoning about the code just gets too hard.

Hmm, I came to suspect that Tk::Wm::Popup has a bug with its use of waitVisibility (giving illusion of synchrony after Post()ing the window), if the dialog is already displayed. Sorry I have not reported it sooner.

I think it may also be causing this bug - Popup is called by Tk::DialogBox::Show, which is used by Tk::ErrorDialog... try

perl -MTk -e '$mw=tkinit; $db=$mw->DialogBox; $mw->after($, [ &showdb, $ ]) for @ARGV; MainLoop; sub showdb { warn "Showing $db for @"; $ret = $db->Show; warn "Returned, Show(@)=$ret\n" }' 100 300

Safe without the second (300ms) call. Broken in the same way with. Minimise the dialog, restore it, click OK and both calls resolve.

Also if the MainWindow is destroyed by close icon, it can give

XS_Tk__Callback_Call error:window ".dialogbox" was deleted before its visibility changed at /software/perl-5.12.2/lib/site_perl/5.12.2/i686-linux-thread-multi/Tk/Widget.pm line 1000.

Maybe a solution is to add code to the Tk::Error subroutine and detect that the dialog is already active. In this case, the ->Show() method shouldn't be called again. Only the dialog text could be changed, and the trace window updated.

I think that might fix the disconnected-button symptoms, but you still lose the text of the first message. Unless you futz around to append the new message.

Another possible solution could be to not re-use the error dialog for multiple errors. But this could result in a cluttered display if many errors happen at the same time.

Would also fix the symptoms.

Matthew

[1] https://github.com/Anacode/ensembl-otter/commit/abaa1b6c

[2] including the one in SelectionGet. I had PropertyNotify events arriving and being handled while the selection was being fetched. When these were starting their own waitVariable event loop, it could get messy. We are doing some unusual stuff with clipboards.

The Wellcome Trust Sanger Institute is operated by Genome Research Limited, a charity registered in England with number 1021457 and a company registered in England with number 2742969, whose registered office is 215 Euston Road, London, NW1 2BE.