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 / Gtk.pm < prev    next >
Encoding:
Perl POD Document  |  2004-01-21  |  8.9 KB  |  334 lines

  1. # $Id: Gtk.pm,v 1.44 2004/01/21 17:27:00 rcaputo Exp $
  2.  
  3. # Gtk-Perl event loop bridge for POE::Kernel.
  4.  
  5. # Empty package to appease perl.
  6. package POE::Loop::Gtk;
  7.  
  8. use strict;
  9.  
  10. # Include common signal handling.
  11. use POE::Loop::PerlSignals;
  12.  
  13. use vars qw($VERSION);
  14. $VERSION = do {my@r=(q$Revision: 1.44 $=~/\d+/g);sprintf"%d."."%04d"x$#r,@r};
  15.  
  16. # Everything plugs into POE::Kernel.
  17. package POE::Kernel;
  18.  
  19. use strict;
  20.  
  21. my $_watcher_timer;
  22. my @fileno_watcher;
  23. my $gtk_init_check;
  24.  
  25. #------------------------------------------------------------------------------
  26. # Loop construction and destruction.
  27.  
  28. sub loop_initialize {
  29.   my $self = shift;
  30.  
  31.   # Must Gnome->init() yourselves, as it takes parameters.
  32.   unless (exists $INC{'Gnome.pm'}) {
  33.     # Gtk can only be initialized once. 
  34.     # So if we've initalized it already, skip the whole deal.
  35.     unless($gtk_init_check) {
  36.       $gtk_init_check++;
  37.  
  38.       my $res = Gtk->init_check();
  39.  
  40.       # Now check whether the init was ok.
  41.       # undefined == icky; TRUE (whatever that means in gtk land) means Ok.
  42.       if (defined $res) {
  43.         Gtk->init();
  44.  
  45.       } else {
  46.         POE::Kernel::_die "Gtk initialization failed. Chances are it couldn't connect to a display. Of course, Gtk doesn't put its error message anywhere I can find so we can't be more specific here.";
  47.       }
  48.     }
  49.   }
  50. }
  51.  
  52. sub loop_finalize {
  53.   foreach my $fd (0..$#fileno_watcher) {
  54.     next unless defined $fileno_watcher[$fd];
  55.     foreach my $mode (MODE_RD, MODE_WR, MODE_EX) {
  56.       POE::Kernel::_warn(
  57.         "Mode $mode watcher for fileno $fd is defined during loop finalize"
  58.       ) if defined $fileno_watcher[$fd]->[$mode];
  59.     }
  60.   }
  61. }
  62.  
  63. #------------------------------------------------------------------------------
  64. # Signal handler maintenance functions.
  65.  
  66. # This function sets us up a signal when whichever window is passed to
  67. # it closes.
  68. sub loop_attach_uidestroy {
  69.   my ($self, $window) = @_;
  70.  
  71.   # Don't bother posting the signal if there are no sessions left.  I
  72.   # think this is a bit of a kludge: the situation where a window
  73.   # lasts longer than POE::Kernel should never occur.
  74.   $window->signal_connect(
  75.     delete_event => sub {
  76.       if ($self->_data_ses_count()) {
  77.         $self->_dispatch_event
  78.           ( $self, $self,
  79.             EN_SIGNAL, ET_SIGNAL, [ 'UIDESTROY' ],
  80.             __FILE__, __LINE__, time(), -__LINE__
  81.           );
  82.       }
  83.       return 0;
  84.     }
  85.   );
  86. }
  87.  
  88. #------------------------------------------------------------------------------
  89. # Maintain time watchers.
  90.  
  91. sub loop_resume_time_watcher {
  92.   my ($self, $next_time) = @_;
  93.   $next_time -= time();
  94.   $next_time *= 1000;
  95.   $next_time = 0 if $next_time < 0;
  96.   $_watcher_timer = Gtk->timeout_add($next_time, \&_loop_event_callback);
  97. }
  98.  
  99. sub loop_reset_time_watcher {
  100.   my ($self, $next_time) = @_;
  101.   # Should always be defined, right?
  102.   Gtk->timeout_remove($_watcher_timer);
  103.   undef $_watcher_timer;
  104.   $self->loop_resume_time_watcher($next_time);
  105. }
  106.  
  107. sub _loop_resume_timer {
  108.   Gtk->idle_remove($_watcher_timer);
  109.   $poe_kernel->loop_resume_time_watcher($poe_kernel->get_next_event_time());
  110. }
  111.  
  112. sub loop_pause_time_watcher {
  113.   # does nothing
  114. }
  115.  
  116. #------------------------------------------------------------------------------
  117. # Maintain filehandle watchers.
  118.  
  119. sub loop_watch_filehandle {
  120.   my ($self, $handle, $mode) = @_;
  121.   my $fileno = fileno($handle);
  122.  
  123.   # Overwriting a pre-existing watcher?
  124.   if (defined $fileno_watcher[$fileno]->[$mode]) {
  125.     Gtk::Gdk->input_remove($fileno_watcher[$fileno]->[$mode]);
  126.     undef $fileno_watcher[$fileno]->[$mode];
  127.   }
  128.  
  129.   if (TRACE_FILES) {
  130.     POE::Kernel::_warn "<fh> watching $handle in mode $mode";
  131.   }
  132.  
  133.   # Register the new watcher.
  134.   $fileno_watcher[$fileno]->[$mode] =
  135.     Gtk::Gdk->input_add( $fileno,
  136.                          ( ($mode == MODE_RD)
  137.                            ? ( 'read',
  138.                                \&_loop_select_read_callback
  139.                              )
  140.                            : ( ($mode == MODE_WR)
  141.                                ? ( 'write',
  142.                                    \&_loop_select_write_callback
  143.                                  )
  144.                                : ( 'exception',
  145.                                    \&_loop_select_expedite_callback
  146.                                  )
  147.                              )
  148.                          ),
  149.                          $fileno
  150.                        );
  151. }
  152.  
  153. sub loop_ignore_filehandle {
  154.   my ($self, $handle, $mode) = @_;
  155.   my $fileno = fileno($handle);
  156.  
  157.   if (TRACE_FILES) {
  158.     POE::Kernel::_warn "<fh> ignoring $handle in mode $mode";
  159.   }
  160.  
  161.   # Don't bother removing a select if none was registered.
  162.   if (defined $fileno_watcher[$fileno]->[$mode]) {
  163.     Gtk::Gdk->input_remove($fileno_watcher[$fileno]->[$mode]);
  164.     undef $fileno_watcher[$fileno]->[$mode];
  165.   }
  166. }
  167.  
  168. sub loop_pause_filehandle {
  169.   my ($self, $handle, $mode) = @_;
  170.   my $fileno = fileno($handle);
  171.  
  172.   if (TRACE_FILES) {
  173.     POE::Kernel::_warn "<fh> pausing $handle in mode $mode";
  174.   }
  175.  
  176.   Gtk::Gdk->input_remove($fileno_watcher[$fileno]->[$mode]);
  177.   undef $fileno_watcher[$fileno]->[$mode];
  178. }
  179.  
  180. sub loop_resume_filehandle {
  181.   my ($self, $handle, $mode) = @_;
  182.   my $fileno = fileno($handle);
  183.  
  184.   # Quietly ignore requests to resume unpaused handles.
  185.   return 1 if defined $fileno_watcher[$fileno]->[$mode];
  186.  
  187.   if (TRACE_FILES) {
  188.     POE::Kernel::_warn "<fh> resuming $handle in mode $mode";
  189.   }
  190.  
  191.   $fileno_watcher[$fileno]->[$mode] =
  192.     Gtk::Gdk->input_add( $fileno,
  193.                          ( ($mode == MODE_RD)
  194.                            ? ( 'read',
  195.                                \&_loop_select_read_callback
  196.                              )
  197.                            : ( ($mode == MODE_WR)
  198.                                ? ( 'write',
  199.                                    \&_loop_select_write_callback
  200.                                  )
  201.                                : ( 'exception',
  202.                                    \&_loop_select_expedite_callback
  203.                                  )
  204.                              )
  205.                          ),
  206.                          $fileno
  207.                        );
  208. }
  209.  
  210. ### Callbacks.
  211.  
  212. # Event callback to dispatch pending events.
  213.  
  214. my $last_time = time();
  215.  
  216. sub _loop_event_callback {
  217.   my $self = $poe_kernel;
  218.  
  219.   if (TRACE_STATISTICS) {
  220.     # TODO - I'm pretty sure the startup time will count as an unfair
  221.     # amout of idleness.
  222.     #
  223.     # TODO - Introducing many new time() syscalls.  Bleah.
  224.     $self->_data_stat_add('idle_seconds', time() - $last_time);
  225.   }
  226.  
  227.   $self->_data_ev_dispatch_due();
  228.   $self->_test_if_kernel_is_idle();
  229.  
  230.   Gtk->timeout_remove($_watcher_timer);
  231.   undef $_watcher_timer;
  232.  
  233.   # Register the next timeout if there are events left.
  234.   if ($self->get_event_count()) {
  235.     $_watcher_timer = Gtk->idle_add(\&_loop_resume_timer);
  236.   }
  237.  
  238.   # And back to Gtk, so we're in idle mode.
  239.   $last_time = time() if TRACE_STATISTICS;
  240.  
  241.   # Return false to stop.
  242.   return 0;
  243. }
  244.  
  245. # Filehandle callback to dispatch selects.
  246. sub _loop_select_read_callback {
  247.   my $self = $poe_kernel;
  248.   my ($handle, $fileno, $hash) = @_;
  249.  
  250.   if (TRACE_FILES) {
  251.     POE::Kernel::_warn "<fh> got read callback for $handle";
  252.   }
  253.  
  254.   $self->_data_handle_enqueue_ready(MODE_RD, $fileno);
  255.   $self->_test_if_kernel_is_idle();
  256.  
  257.   # Return false to stop... probably not with this one.
  258.   return 0;
  259. }
  260.  
  261. sub _loop_select_write_callback {
  262.   my $self = $poe_kernel;
  263.   my ($handle, $fileno, $hash) = @_;
  264.  
  265.   if (TRACE_FILES) {
  266.     POE::Kernel::_warn "<fh> got write callback for $handle";
  267.   }
  268.  
  269.   $self->_data_handle_enqueue_ready(MODE_WR, $fileno);
  270.   $self->_test_if_kernel_is_idle();
  271.  
  272.   # Return false to stop... probably not with this one.
  273.   return 0;
  274. }
  275.  
  276. sub _loop_select_expedite_callback {
  277.   my $self = $poe_kernel;
  278.   my ($handle, $fileno, $hash) = @_;
  279.  
  280.   if (TRACE_FILES) {
  281.     POE::Kernel::_warn "<fh> got expedite callback for $handle";
  282.   }
  283.  
  284.   $self->_data_handle_enqueue_ready(MODE_EX, $fileno);
  285.   $self->_test_if_kernel_is_idle();
  286.  
  287.   # Return false to stop... probably not with this one.
  288.   return 0;
  289. }
  290.  
  291. #------------------------------------------------------------------------------
  292. # The event loop itself.
  293.  
  294. sub loop_do_timeslice {
  295.   die "doing timeslices currently not supported in the Gtk loop";
  296. }
  297.  
  298. sub loop_run {
  299.   Gtk->main;
  300. }
  301.  
  302. sub loop_halt {
  303.   Gtk->main_quit();
  304. }
  305.  
  306. 1;
  307.  
  308. __END__
  309.  
  310. =head1 NAME
  311.  
  312. POE::Loop::Event - a bridge that supports Gtk's event loop from POE
  313.  
  314. =head1 SYNOPSIS
  315.  
  316. See L<POE::Loop>.
  317.  
  318. =head1 DESCRIPTION
  319.  
  320. This class is an implementation of the abstract POE::Loop interface.
  321. It follows POE::Loop's public interface exactly.  Therefore, please
  322. see L<POE::Loop> for its documentation.
  323.  
  324. =head1 SEE ALSO
  325.  
  326. L<POE>, L<POE::Loop>, L<Gtk>
  327.  
  328. =head1 AUTHORS & LICENSING
  329.  
  330. Please see L<POE> for more information about authors, contributors,
  331. and POE's licensing.
  332.  
  333. =cut
  334.