home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / xampp / xampp-perl-addon-1.4.9-installer.exe / TkCommon.pm < prev    next >
Encoding:
Perl POD Document  |  2004-01-21  |  5.5 KB  |  218 lines

  1. # $Id: TkCommon.pm,v 1.6 2004/01/21 17:27:01 rcaputo Exp $
  2.  
  3. # The common bits of our system-specific Tk event loops.  This is
  4. # everything but file handling.
  5.  
  6. # Empty package to appease perl.
  7. package POE::Loop::TkCommon;
  8.  
  9. # Include common signal handling.
  10. use POE::Loop::PerlSignals;
  11.  
  12. use vars qw($VERSION);
  13. $VERSION = do {my@r=(q$Revision: 1.6 $=~/\d+/g);sprintf"%d."."%04d"x$#r,@r};
  14.  
  15. use Tk 800.021;
  16. use 5.00503;
  17.  
  18. # Everything plugs into POE::Kernel.
  19. package POE::Kernel;
  20.  
  21. use strict;
  22.  
  23. my $_watcher_timer;
  24.  
  25. #------------------------------------------------------------------------------
  26. # Signal handler maintenance functions.
  27.  
  28. sub loop_attach_uidestroy {
  29.   my ($self, $window) = @_;
  30.  
  31.   $window->OnDestroy
  32.     ( sub {
  33.         if ($self->_data_ses_count()) {
  34.           $self->_dispatch_event
  35.             ( $self, $self,
  36.               EN_SIGNAL, ET_SIGNAL, [ 'UIDESTROY' ],
  37.               __FILE__, __LINE__, time(), -__LINE__
  38.             );
  39.         }
  40.       }
  41.     );
  42. }
  43.  
  44. #------------------------------------------------------------------------------
  45. # Maintain time watchers.
  46.  
  47. sub loop_resume_time_watcher {
  48.   my ($self, $next_time) = @_;
  49.   $next_time -= time();
  50.  
  51.   if (defined $_watcher_timer) {
  52.     $_watcher_timer->cancel();
  53.     undef $_watcher_timer;
  54.   }
  55.  
  56.   $next_time = 0 if $next_time < 0;
  57.   $_watcher_timer =
  58.     $poe_main_window->after($next_time * 1000, [\&_loop_event_callback]);
  59. }
  60.  
  61. sub loop_reset_time_watcher {
  62.   my ($self, $next_time) = @_;
  63.   $self->loop_resume_time_watcher($next_time);
  64. }
  65.  
  66. sub loop_pause_time_watcher {
  67.   my $self = shift;
  68.   $_watcher_timer->stop() if defined $_watcher_timer;
  69. }
  70.  
  71. # Tk's alarm callbacks seem to have the highest priority.  That is, if
  72. # $widget->after is constantly scheduled for a period smaller than the
  73. # overhead of dispatching it, then no other events are processed.
  74. # That includes afterIdle and even internal Tk events.
  75.  
  76. # Tk timer callback to dispatch events.
  77.  
  78. my $last_time = time();
  79.  
  80. sub _loop_event_callback {
  81.   if (TRACE_STATISTICS) {
  82.     # TODO - I'm pretty sure the startup time will count as an unfair
  83.     # amout of idleness.
  84.     #
  85.     # TODO - Introducing many new time() syscalls.  Bleah.
  86.     $poe_kernel->_data_stat_add('idle_seconds', time() - $last_time);
  87.   }
  88.  
  89.   $poe_kernel->_data_ev_dispatch_due();
  90.  
  91.   # As was mentioned before, $widget->after() events can dominate a
  92.   # program's event loop, starving it of other events, including Tk's
  93.   # internal widget events.  To avoid this, we'll reset the event
  94.   # callback from an idle event.
  95.  
  96.   # Register the next timed callback if there are events left.
  97.  
  98.   if ($poe_kernel->get_event_count()) {
  99.  
  100.     # Cancel the Tk alarm that handles alarms.
  101.  
  102.     if (defined $_watcher_timer) {
  103.       $_watcher_timer->cancel();
  104.       undef $_watcher_timer;
  105.     }
  106.  
  107.     # Replace it with an idle event that will reset the alarm.
  108.  
  109.     $_watcher_timer = $poe_main_window->afterIdle(
  110.       [
  111.         sub {
  112.           $_watcher_timer->cancel();
  113.           undef $_watcher_timer;
  114.  
  115.           my $next_time = $poe_kernel->get_next_event_time();
  116.           if (defined $next_time) {
  117.             $next_time -= time();
  118.             $next_time = 0 if $next_time < 0;
  119.  
  120.             $_watcher_timer = $poe_main_window->after(
  121.               $next_time * 1000,
  122.               [\&_loop_event_callback]
  123.             );
  124.           }
  125.         }
  126.       ],
  127.     );
  128.  
  129.     # POE::Kernel's signal polling loop always keeps one event in the
  130.     # queue.  We test for an idle kernel if the queue holds only one
  131.     # event.  A more generic method would be to keep counts of user
  132.     # vs. kernel events, and GC the kernel when the user events drop
  133.     # to 0.
  134.  
  135.     if ($poe_kernel->get_event_count() == 1) {
  136.       $poe_kernel->_test_if_kernel_is_idle();
  137.     }
  138.   }
  139.  
  140.   # Make sure the kernel can still run.
  141.   else {
  142.     $poe_kernel->_test_if_kernel_is_idle();
  143.   }
  144.  
  145.   # And back to Tk, so we're in idle mode.
  146.   $last_time = time() if TRACE_STATISTICS;
  147. }
  148.  
  149. #------------------------------------------------------------------------------
  150. # Tk traps errors in an effort to survive them.  However, since POE
  151. # does not, this leaves us in a strange, inconsistent state.  Here we
  152. # re-trap the errors and rethrow them as UIDESTROY.
  153.  
  154. sub Tk::Error {
  155.   my $window = shift;
  156.   my $error  = shift;
  157.  
  158.   if (Tk::Exists($window)) {
  159.     my $grab = $window->grab('current');
  160.     $grab->Unbusy if defined $grab;
  161.   }
  162.   chomp($error);
  163.   POE::Kernel::_warn "Tk::Error: $error\n " . join("\n ",@_)."\n";
  164.  
  165.   if ($poe_kernel->_data_ses_count()) {
  166.     $poe_kernel->_dispatch_event
  167.       ( $poe_kernel, $poe_kernel,
  168.         EN_SIGNAL, ET_SIGNAL, [ 'UIDESTROY' ],
  169.         __FILE__, __LINE__, time(), -__LINE__
  170.       );
  171.   }
  172. }
  173.  
  174. #------------------------------------------------------------------------------
  175. # The event loop itself.
  176.  
  177. sub loop_do_timeslice {
  178.   die "doing timeslices currently not supported in the Tk loop";
  179. }
  180.  
  181. sub loop_run {
  182.   Tk::MainLoop();
  183. }
  184.  
  185. sub loop_halt {
  186.   undef $_watcher_timer;
  187.   $poe_main_window->destroy();
  188. }
  189.  
  190. 1;
  191.  
  192. __END__
  193.  
  194. =head1 NAME
  195.  
  196. POE::Loop::TkCommon - common features of POE's Tk event loop bridges
  197.  
  198. =head1 SYNOPSIS
  199.  
  200. See L<POE::Loop>.
  201.  
  202. =head1 DESCRIPTION
  203.  
  204. This class is an implementation of the abstract POE::Loop interface.
  205. It follows POE::Loop's public interface exactly.  Therefore, please
  206. see L<POE::Loop> for its documentation.
  207.  
  208. =head1 SEE ALSO
  209.  
  210. L<POE>, L<POE::Loop>, L<Tk>
  211.  
  212. =head1 AUTHORS & LICENSING
  213.  
  214. Please see L<POE> for more information about authors, contributors,
  215. and POE's licensing.
  216.  
  217. =cut
  218.