=head1 ABSTRACT Very simple IO signaling system for POE and Wx Loops. =head1 DESCRIPTION This module is very similiar to the POE::Component::SimpleLog logging system. It uses the same type of register/unregister structure. It was partially inspired by the POE: Cookbook - Broadcasting Events and a long bloody fight of trying to make Wx events talk with POE sessions. This module does not do generate or react to signal calls, it simply routes them to the designated place ( Evt methods ). The normal routing is between a Poe session and a Wx window. However, it is also possible to send signals between two Wx windows. You have to configure and register a signal that you desire to use. The configuration describes the signal behavior and channel you want. The default channel is 'MAIN', so no channel declaration is require if using non-conflicting signals. For routing between Wx window, a special channel 'FRAME_TO_FRAME' is used to indicate that the signal is passed directly to another Wx window. The signal must be coordinated on both sides, Poe and Wx, so each side must register. Registering for a signal sets up a 'watcher' state so that a signal is broadcast to each registered watcher. A signal can have multiple dispatches, but only one source. Once the signal task has been completed, the task(er) sends a call to 'end_signal' to clear the signal state and to dispatch any completion notices. The completion notices are registered normally as a registered [receiving] WxFrame. No special channel is set for Poe to Poe signaling, though that should be an easy add, if needed. This signaling method only transfers a signal [key] with a single piece of signal data. The intent is not to pass data arrays back and forth. If you need to pass data and state around, then I would use some type of data and state manager to handle this task. I use shared pointers to state and data objects within my production app. Note that signals are triggered between Poe and Wx sessions by way of a 'pulse' method per Ed Heil's wxpoe.pl sample code. Ed's sample code has been modified in the example to integrate the WxPoeIO signal methods. The code changes were cut from production code so the examples may need minor tweaks to run without warnings. The standard way to use this module is to do this: use POE; use POE::Component::WxPoeIO; #### ## Declare vars #### my $MyApp_name = 'WxPoeTestApp'; my $signal_keys = {'signal1'=>1,'signal2'=>2); my $signal_queue = []; POE::Component::WxPoeIO->new( ... ); my $MyApp = $MyApp_name->new(); POE::Session->create( ... ); POE::Kernel->loop_run(); POE::Kernel->run(); =head2 Starting WxPoeIO To start WxPoeIO, just call it's 'new' method: POE::Component::WxPoeIO->new( 'ALIAS' => 'WxPoeIO', 'SIGNAL_KEYS' => $signal_keys, 'SIGNAL_QUEUE' => $signal_queue, ); This method will die on error or return success. This constructor accepts only 3 options. =over 4 =item C This will set the alias WxPoeIO uses in the POE Kernel. This will default TO "WxPoeIO" =item C This is a hash pointer to a list of signal keys to be configured and registered later. =item C This is an array pointer to the signal queue that is shared between the Wx windows and the main Poe session. =back =head2 Evt_method This is the subroutine/method declaration that WxPoeIO uses to dispatch signals. It must match an existing method within the object or session. =over 4 =item C This task accepts 6 arguments: SIGNAL_KEY -> The name/key of the signal to register SIGNAL_CHANNEL -> The channel the signal will use. Provides locking of channel to avoid signal conflicts LATCH -> The signal can be latch until completion to prevent multiple signal sends TIMEOUT -> The timeout in secs until a latch is removed - in case the signal dies in a session LOCK -> The channel can be lock until completion to prevent signal conflicts on the same channel RETRIES -> The number of times the signal will retry a lock before dying and clearing the lock Note: TIMEOUT and RETRIES are not both allowed to be null. One or the other will clear the latch/lock. If a hang has occurred in a session, this will not be fixed. An example: $_[KERNEL]->post( 'WxPoeIO', 'CONFIG_SIGNAL', SIGNAL_KEY => 'MySig', SIGNAL_CHANNEL => 'Start_Remote_Session', [LATCH => 1,] [LOCK => 1,] [TIMEOUT => undef,] [RETRIES => 100,] ); The latching and lock is not super complex. The latch prevents new signals with the same key from being accepted. The lock allows similar signals to share the same channel (i.e., session method) but keeps new signals from stepping on a working session. The lock checks for is_noisy channel (an active session on the channel). If is_noisy, then if the channel is not yet locked, it will be locked. Retries kills the signal by clearing all signal states. This does not fix problems within the session that caused signal not to terminate. A signal must be configure before a session or a frame can register to use that signal. This is an extra step, but ensures the Poe sessions and Wx frames are registering for the same thing. =item C This task accepts 3 arguments: SIGNAL_KEY -> The name/key of the signal to register SESSION -> The session where the signal will go ( Also accepts Session ID's ) EVT_METHOD -> The method within the session that will be called upon the signal event The registering for a signal will fail if one of the above values are undefined. The signal must be pre-configured. Registration links the POE session side of the communication. Evt_methods that receive the signals will get these: ARG0 -> SIGNAL_KEY ARG1 -> SIGNAL_VALUE Here's an example: $_[KERNEL]->post( 'WxPoeIO', 'REGISTER_SESSION', SIGNAL_KEY => 'ClickMe', SESSION => $_[SESSION], EVT_METHOD => 'start_this', ); This is the session subroutine that will get the ClickMe signal sub start_this { # Get the arguments my( $sigkey, $sigvalue ) = @_[ ARG0 .. ARG1 ]; print STDERR "Signal [$sigkey] want to start this -> [$sigvalue]\n"; } =item C This task accepts 3 to 5 arguments: SIGNAL_KEY -> The name/key of the signal to register EVT_METHOD -> The method within the wxframe that will be called upon the signal event [WXFRAME_IDENT] -> The identification of the wxframe where the 'end signal' will go [WXFRAME_MGR_TOGGLE] -> A toggle to use a wxframe manager to manage method calls [WXFRAME_OBJ] -> The stored pointer to the wxframe object The registering for a signal will fail if the SIGNAL_KEY or EVT_METHOD values are undefined. The signal must be pre-configured. Registration links the WxFrame side of the communication. Evt_methods that receive the logs will get these: ARG0 -> SIGNAL_KEY ARG1 -> SIGNAL_VALUE An example: $_[KERNEL]->post( 'WxPoeIO', 'REGISTER_WXFRAME', SIGNAL_KEY => 'ClickMe', WXFRAME_IDENT => 'Frame 1', EVT_METHOD => 'ShowMyClick', WXFRAME_MGR_TOGGLE => undef, ); This is the wxframe subroutine that will get the ClickMe signal sub ShowMyClick { # using the passed in argument array and indexes if($_[1]=~/^clickme/i) { $_[0]->{text_show}->AppendText($_[2]."\n"); } return; } =item C This task uses no arguments: This method pulls new signals from the signal queue (shifting the heap array pointer) and sends the signal (and signal value) to the manage_to_poe method. When the queue is empty, the task exits. An example: $_[KERNEL]->post( 'WxPoeIO', 'TRIGGER_SIGNALS' ); =item C This task accepts 2 arguments: ARG0 -> signal key ARG1 -> end value This method normally completes the signaling task. If the sigal requires no latch or locking then it is not necessary to end the signal. But typically it is appropriate to send back a completion status or to remove locks on the signal channel. Inter wx frame communication will not use an end_signal. This should not be necessary because the signal result should be visually presented to the user. An example: $_[KERNEL]->post( 'WxPoeIO', 'END_SIGNAL', $sigkey, $endsigvalue ); Where, $sigkey is the relevant SIGNAL_KEY value. And $endsigvalue is the variable sent back to wxframe. NOTE: The type of the $sigvalue is not restricted and there is no checking of this value. As long as both sides of the communication can process this variable, you will be fine. This value (variable) is not intended for the passing of large data structures. If you have this need, then you should create a data management object to be shared across wxframes and sessions. =item C The pointer for the signal queue array should be passed in when the module is started. However, a 'default' pointer can be exported (and stored) so that signalkeys are properly pushed onto the HEAP signal queue array. An example: if( !defined $signal_queue_ptr ) { $_[KERNEL]->post( 'WxPoeIO', 'EXPORT_SIQ_QUEUE_PTR', $signal_queue_ptr ); } The $signal_queue_ptr variable will now match the signal queue array pointer within the POE $_[HEAP]; =item C This is the generic SHUTDOWN routine, it will stop all logging. An example: $_[KERNEL]->post( 'WxPoeIO', 'SHUTDOWN' ); =back =head2 WxPoeIO Notes Case matters. All of the options are uppercase. You can enable debugging mode by doing this: sub POE::Component::WxPoeIO::DEBUG () { 1 } use POE::Component::WxPoeIO; =head2 EXPORT Nothing. =head1 SEE ALSO L =head1 AUTHOR Apocalypse Eapocal@cpan.orgE =head1 COPYRIGHT AND LICENSE Copyright 2014 by Sebastian This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Source credit goes to the POE: Cookbook - Broadcasting Events for the signal channel registry concept. The code structure comes from the POE::Component::SimpleLog by Apocalypse. The WxPoe and pulse concept is from the wxpoe2.pl example code by Ed Heil. =cut