POE::Loop::Wx - a bridge that supports wxPerl's event loop from POE


POE-Loop-Wx documentation Contained in the POE-Loop-Wx distribution.

Index


Code Index:

NAME

Top

POE::Loop::Wx - a bridge that supports wxPerl's event loop from POE

SYNOPSIS

Top

See POE::Loop.

DESCRIPTION

Top

This class is an implementation of the abstract POE::Loop interface. It follows POE::Loop's public interface exactly. Therefore, please see POE::Loop for its documentation.

EXAMPLES

Top

See the examples directory for a simple Wx/POE application that demonstrates subscribe/publish data amongst frames as well as use PoCoCl::UserAgent for non-blocking parallel data fetching that cooperates with Wx.

TODO

Top

More examples, add tests.

SEE ALSO

Top

POE, POE::Loop, Wx

AUTHORS

Top

Mike Schroeder <mike-cpan@donorware.com> Ed Heil <ed-cpan@donorware.com>

ACKNOWLEGEMENTS

Top

Special thanks to Mattia Barbon for getting the initial version of this put together and encouraging me to get this onto CPAN.

Please see POE for more information about authors, contributors, and POE's licensing. Please see Wx for more information about wxPerl and wxWidgets.


POE-Loop-Wx documentation Contained in the POE-Loop-Wx distribution.

#############################################################################
## Name:        Wx.pm
## Purpose:     POE::Loop::Wx, wxPerl event loop for POE
## Author:      Mattia Barbon, 
## Created:     26/05/2003
## Updated by:  Mike Schroeder - to be compatible with POE 3.003
## Updated:     21/12/2004
## RCS-ID:      $Id: Wx.pm,v 1.9 2007/11/29 16:33:19 mike Exp $
## Copyright:   (c) 2003 Mattia Barbon
## Note:        Part of the code comes almost straight from
##              POE::Loop::Gtk and POE::Loop::Select
## Licence:     This program is free software; you can redistribute it and/or
##              modify it under the same terms as Perl itself
#############################################################################

package POE::Loop::Wx;

use Wx;
use strict;
use vars qw($VERSION); 
use POE::Loop::PerlSignals;

$VERSION = "0.04";

package POE::Kernel;

use strict;

# Declare which event loop bridge is being used, but first ensure that
# no other bridge has been loaded.

BEGIN {
  die( "POE can't use Wx and " . &POE_LOOP_NAME . "\n" )
    if defined &POE_LOOP;
};

sub POE_LOOP () { LOOP_WX }

my @loop_vectors = ("", "", "");
my %loop_filenos;
my $time_watcher_timer;
my $file_watcher_timer;

###############################################################################
# Administrative functions
###############################################################################

sub loop_initialize {
    my $self = shift;

    # Initialize the vectors as vectors.
    @loop_vectors = ( "", "", "" );
    vec($loop_vectors[MODE_RD], 0, 1) = 0;
    vec($loop_vectors[MODE_WR], 0, 1) = 0;
    vec($loop_vectors[MODE_EX], 0, 1) = 0;

    # start file polling timer
    $file_watcher_timer = POE::Loop::Wx::PollTimer->new;
    $file_watcher_timer->Start( 50, 0 );
}

sub loop_finalize {
    my $self = shift;

    # This is "clever" in that it relies on each symbol on the left to
    # be stringified by the => operator.
    my %kernel_modes =
      ( MODE_RD => MODE_RD,
        MODE_WR => MODE_WR,
        MODE_EX => MODE_EX,
      );

    while (my ($mode_name, $mode_offset) = each(%kernel_modes)) {
        my $bits = unpack("b*", $loop_vectors[$mode_offset]);
        if (index($bits, "1") >= 0) {
            warn "<rc> LOOP VECTOR LEAK: $mode_name = $bits\a\n";
        }
    }

    $time_watcher_timer->Destroy;
    $file_watcher_timer->Destroy;
    undef $time_watcher_timer;
    undef $file_watcher_timer;
}

sub loop_do_timeslice {
    die "doing timeslices currently not supported in the Wx loop";
}

sub loop_run {
    Wx::wxTheApp()->MainLoop;
}

sub loop_halt {
    Wx::wxTheApp->ExitMainLoop if Wx::wxTheApp;
}

sub loop_attach_uidestroy {
    my( $self, $window ) = @_;

    # Don"t bother posting the signal if there are no sessions left.  I
    # think this is a bit of a kludge: the situation where a window
    # lasts longer than POE::Kernel should never occur.
    Wx::Event::EVT_CLOSE( $window,
                          sub {
                              if( $self->_data_ses_count() ) {
                                  $self->_dispatch_event
                                    ( $self, $self,
                                      EN_SIGNAL, ET_SIGNAL, [ "UIDESTROY" ],
                                      __FILE__, __LINE__, time(), -__LINE__
                                    );
                              }
                              return undef;
                          }
                        );
}

###############################################################################
# Alarm or timer functions
###############################################################################

sub loop_reset_time_watcher {
    my( $self, $next_time ) = @_;

    if( $time_watcher_timer ) {
        $time_watcher_timer->Destroy;
        undef $time_watcher_timer;
    }

    $time_watcher_timer = POE::Loop::Wx::Timer->new;
    $self->loop_resume_time_watcher( $next_time );
}

BEGIN {
    if( $^O eq "MSWin32" or $^O eq 'darwin'  ) {
        eval "sub MIN_TIME() { 1 }";
    } else {
        eval "sub MIN_TIME() { 0 }";
    }
}

sub loop_resume_time_watcher {
    my( $self, $next_time ) = @_;
    $time_watcher_timer = POE::Loop::Wx::Timer->new
        unless $time_watcher_timer;

    $next_time -= time();
    $next_time *= 1000;
    $next_time = MIN_TIME if $next_time <= MIN_TIME;

    $time_watcher_timer->Start( $next_time, 1 );
}

sub loop_pause_time_watcher {
    $time_watcher_timer->Stop;
}

###############################################################################
# File activity functions; similar to POE::Loop::Select
###############################################################################

#------------------------------------------------------------------------------
# Maintain filehandle watchers.

sub loop_watch_filehandle {
    my( $self, $handle, $mode ) = @_;
    my $fileno = fileno( $handle );

    vec( $loop_vectors[$mode], $fileno, 1 ) = 1;
    $loop_filenos{$fileno} |= ( 1 << $mode );
}

sub loop_ignore_filehandle {
    my( $self, $handle, $mode ) = @_;
    my $fileno = fileno( $handle );

    vec( $loop_vectors[$mode], $fileno, 1 ) = 0;
    $loop_filenos{$fileno} &= ~ ( 1 << $mode );
}

sub loop_pause_filehandle {
    my( $self, $handle, $mode ) = @_;
    my $fileno = fileno( $handle );

    vec( $loop_vectors[$mode], $fileno, 1 ) = 0;
    $loop_filenos{$fileno} &= ~ ( 1 << $mode );
}

sub loop_resume_filehandle {
    my( $self, $handle, $mode ) = @_;
    my $fileno = fileno( $handle );

    vec( $loop_vectors[$mode], $fileno, 1 ) = 1;
    $loop_filenos{$fileno} |= ( 1 << $mode );
}

# End of stuff similar to POE::Loop::Select

package POE::Loop::Wx::Timer;

use strict;
use base "Wx::Timer";

sub Notify {
    package POE::Kernel;

    my $self = $poe_kernel;

    $self->_data_ev_dispatch_due();
    $self->_test_if_kernel_is_idle();

    # Register the next timeout if there are events left.
    if( $self->get_event_count() ) {
        $self->loop_resume_time_watcher( $self->get_next_event_time() );
    }
}

package POE::Loop::Wx::PollTimer;

use strict;
use base "Wx::Timer";

sub Notify {
    package POE::Kernel;

    my $self = $poe_kernel;

    # Determine which files are being watched.
    my @filenos = ();
    while( my( $fd, $mask ) = each( %loop_filenos ) ) {
        push( @filenos, $fd ) if $mask;
    }

    return unless @filenos;

    # Check filehandles, or wait for a period of time to elapse.
    my $hits = CORE::select( my $rout = $loop_vectors[MODE_RD],
                             my $wout = $loop_vectors[MODE_WR],
                             my $eout = $loop_vectors[MODE_EX],
                             0,
                           );

    return unless $hits > 0;

    # This is where they"re gathered.  It"s a variant on a neat
    # hack Silmaril came up with.
    my( @rd_selects, @wr_selects, @ex_selects );
    foreach ( @filenos ) {
        push( @rd_selects, $_ ) if vec( $rout, $_, 1 );
        push( @wr_selects, $_ ) if vec( $wout, $_, 1 );
        push( @ex_selects, $_ ) if vec( $eout, $_, 1 );
    }

    @rd_selects and
      $self->_data_handle_enqueue_ready( MODE_RD, @rd_selects );
    @wr_selects and
      $self->_data_handle_enqueue_ready( MODE_WR, @wr_selects );
    @ex_selects and
      $self->_data_handle_enqueue_ready( MODE_EX, @ex_selects );
}

1;

__END__