Skip Menu |

This queue is for tickets about the Tk CPAN distribution.

Report information
The Basics
Id: 50330
Status: open
Priority: 0/
Queue: Tk

People
Owner: Nobody in particular
Requestors: lamprecht [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: 804.028
Fixed in: (no value)



Subject: Tk::Button::Invoke() calls idletasks causing race conditions
Tk::Button::Invoke() calls idletasks in between saving and restoring Buttons -state and before actually invoking the callback. This changes order of events processed - and worse it overwrites any changes made to Buttons -state from other pending events. Here is an example: use strict; use warnings; use Tk; use Tk::Button; my $b; my $main= MainWindow->new(); $b = $main->Button( -text=> 'test', -command=> sub{print "do work\n"; }, )->pack(); $b->focus ; $main->update; $main->afterIdle(sub{$b->eventGenerate('<Return>')}); $main->afterIdle(sub{$b->configure(-state => 'disabled'); print "set buttons state to disabled\n"; } ); MainLoop; expected output: do work set buttons state to disabled resulting in a disabled Button after startup. instead I see: set buttons state to disabled do work and an active Button displayed. Take a look at Tk::Button::Invoke() (Buttons <Return> handler) sub Invoke { my $w = shift; if ($w->cget('-state') ne 'disabled') { my $oldRelief = $w->cget('-relief'); my $oldState = $w->cget('-state'); $w->configure('-state' => 'active', '-relief' => 'sunken'); $w->idletasks; $w->after(100); my $state = $w->cget('-state'); $w->configure('-state' => $oldState, '-relief' => $oldRelief); $w->invoke; } } The problem is obvious: commenting out the idletasks call fixes behaviour but then the virtual 'ButtonPress' action won't get displayed. Is there any alternative to idletasks in the library, which would make it possible to update the Buttons view without processing other IDLE events?? Cheers, Christoph
On Thu Oct 08 08:45:19 2009, LAMPRECHT wrote: Show quoted text
> Tk::Button::Invoke() calls idletasks in between saving and restoring > Buttons -state and before actually invoking the callback. This changes > order of events processed - and worse it overwrites any changes made to > Buttons -state from other pending events. > > Here is an example: > use strict; > use warnings; > use Tk; > use Tk::Button; > my $b; > my $main= MainWindow->new(); > $b = $main->Button( > -text=> 'test', > -command=> sub{print "do work\n"; }, > )->pack(); > > $b->focus ; > $main->update; > > $main->afterIdle(sub{$b->eventGenerate('<Return>')}); > $main->afterIdle(sub{$b->configure(-state => 'disabled'); > print "set buttons state to disabled\n"; > } > ); > MainLoop; > > expected output: > > do work > set buttons state to disabled > > resulting in a disabled Button after startup. > > instead I see: > > set buttons state to disabled > do work > > and an active Button displayed. > > Take a look at Tk::Button::Invoke() (Buttons <Return> handler) > > sub Invoke > { > my $w = shift; > > if ($w->cget('-state') ne 'disabled') > { > my $oldRelief = $w->cget('-relief'); > my $oldState = $w->cget('-state'); > $w->configure('-state' => 'active', '-relief' => 'sunken'); > $w->idletasks; > > $w->after(100); > my $state = $w->cget('-state'); > $w->configure('-state' => $oldState, '-relief' => $oldRelief); > $w->invoke; > } > } > > The problem is obvious: commenting out the idletasks call fixes > behaviour but then the virtual 'ButtonPress' action won't get displayed. > Is there any alternative to idletasks in the library, which would make > it possible to update the Buttons view without processing other IDLE > events?? > > Cheers, Christoph
It seems that this is possible: just replace the $w->idletasks call by while ($w->DoOneEvent(Tk::DONT_WAIT()|Tk::WINDOW_EVENTS())) {} With this change in Tk::Button::Invoke, the order is as expected. However, as this would be a rather deep change I am somewhat reluctant to put it in the next Tk release. But I will "monkeypatch" my favorite Tk apps to use this change and do some thorough testing. Regards, Slaven
Subject: Re: [rt.cpan.org #50330] Tk::Button::Invoke() calls idletasks causing race conditions
Date: Sat, 17 Oct 2009 22:57:38 +0200
To: bug-Tk [...] rt.cpan.org
From: Ch Lamprecht <ch.l.ngre [...] online.de>
Slaven_Rezic via RT schrieb: Show quoted text
Show quoted text
> > It seems that this is possible: just replace the $w->idletasks call by > > while ($w->DoOneEvent(Tk::DONT_WAIT()|Tk::WINDOW_EVENTS())) {} > > With this change in Tk::Button::Invoke, the order is as expected.
Hi, thanks for looking into this. Yes, the order is as expected but then the Buttons reaction to <Return> is to call the callback without visualizing the ButtonPress. (You can have the same effect by commenting out the idletasks() call. Cheers, Christoph