source: perl/lib/BarnOwl.pm @ 6deb32b

Last change on this file since 6deb32b was 6deb32b, checked in by Jason Gross <jgross@mit.edu>, 7 years ago
Describe get_variable_info
  • Property mode set to 100644
File size: 24.0 KB
Line 
1use strict;
2use warnings;
3
4package BarnOwl;
5
6use base qw(Exporter);
7our @EXPORT_OK = qw(command getcurmsg getnumcols getnumlines getidletime
8                    register_idle_watcher unregister_idle_watcher
9                    zephyr_getsender zephyr_getrealm zephyr_zwrite
10                    zephyr_stylestrip zephyr_smartstrip_user zephyr_getsubs
11                    queue_message admin_message
12                    start_edit
13                    start_question start_password start_edit_win
14                    get_data_dir get_config_dir popless_text popless_ztext
15                    error debug
16                    create_style getnumcolors wordwrap
17                    message_matches_filter
18                    get_variable_info
19                    add_dispatch remove_dispatch
20                    add_io_dispatch remove_io_dispatch
21                    new_command
22                    new_variable_int new_variable_bool new_variable_string
23                    new_variable_enum
24                    quote redisplay);
25our %EXPORT_TAGS = (all => \@EXPORT_OK);
26
27BEGIN {
28# bootstrap in C bindings and glue
29    *owl:: = \*BarnOwl::;
30    bootstrap BarnOwl 1.2;
31};
32
33use lib(get_data_dir() . "/lib");
34use lib(get_config_dir() . "/lib");
35
36use Glib;
37use AnyEvent;
38
39use BarnOwl::Hook;
40use BarnOwl::Hooks;
41use BarnOwl::Message;
42use BarnOwl::Style;
43use BarnOwl::Zephyr;
44use BarnOwl::Timer;
45use BarnOwl::Editwin;
46use BarnOwl::Completion;
47use BarnOwl::Help;
48
49use List::Util qw(max);
50use Tie::RefHash;
51
52=head1 NAME
53
54BarnOwl
55
56=head1 DESCRIPTION
57
58The BarnOwl module contains the core of BarnOwl's perl
59bindings. Source in this module is also run at startup to bootstrap
60BarnOwl by defining things like the default style.
61
62=for NOTE
63These following functions are defined in perlglue.xs. Keep the
64documentation here in sync with the user-visible commands defined
65there!
66
67=head2 command STRING
68
69Executes a BarnOwl command in the same manner as if the user had
70executed it at the BarnOwl command prompt. If the command returns a
71value, return it as a string, otherwise return undef.
72
73=head2 getcurmsg
74
75Returns the current message as a C<BarnOwl::Message> subclass, or
76undef if there is no message selected
77=head2 getnumcols
78
79Returns the width of the display window BarnOwl is currently using
80
81=head2 getidletime
82
83Returns the length of time since the user has pressed a key, in
84seconds.
85
86=head2 zephyr_getrealm
87
88Returns the zephyr realm BarnOwl is running in
89
90=head2 zephyr_getsender
91
92Returns the fully-qualified name of the zephyr sender BarnOwl is
93running as, e.g. C<nelhage@ATHENA.MIT.EDU>
94
95=head2 zephyr_zwrite COMMAND MESSAGE
96
97Sends a zephyr programmatically. C<COMMAND> should be a C<zwrite>
98command line, and C<MESSAGE> is the zephyr body to send.
99
100=cut
101
102sub zephyr_zwrite {
103    my ($command, $message) = @_;
104    my $ret = BarnOwl::Internal::zephyr_zwrite($command, $message);
105    die "Error sending zephyr" unless $ret == 0;
106}
107
108=head2 ztext_stylestrip STRING
109
110Strips zephyr formatting from a string and returns the result
111
112=head2 zephyr_getsubs
113
114Returns the list of subscription triples <class,instance,recipient>,
115separated by newlines.
116
117=head2 queue_message MESSAGE
118
119Enqueue a message in the BarnOwl message list, logging it and
120processing it appropriately. C<MESSAGE> should be an instance of
121BarnOwl::Message or a subclass.
122
123=head2 admin_message HEADER BODY
124
125Display a BarnOwl B<Admin> message, with the given header and body.
126
127=head2 start_edit %ARGS
128
129Displays a prompt on the screen and lets the user enter text,
130and calls a callback when the editwin is closed.
131
132C<%ARGS> must contain the following keys:
133
134=over 4
135
136=item prompt
137
138The line to display on the screen
139
140=item type
141
142One of:
143
144=over 4
145
146=item edit_win
147
148Displays the prompt on a line of its own and opens the edit_win.
149
150=item question
151
152Displays prompt on the screen and lets the user enter a line of
153text.
154
155=item password
156
157Like question, but echoes the user's input as C<*>s when they
158input.
159
160=back
161
162=item callback
163
164A Perl subroutine that is called when the user closes the edit_win.
165C<CALLBACK> gets called with two parameters: the text the user entered,
166and a C<SUCCESS> boolean parameter which is false if the user canceled
167the edit_win and true otherwise.
168
169=back
170
171=head2 start_question PROMPT CALLBACK
172
173=head2 start_password PROMPT CALLBACK
174
175=head2 start_edit_win PROMPT CALLBACK
176
177Roughly equivalent to C<start_edit> called with the appropriate parameters.
178C<CALLBACK> is only called on success, for compatibility.
179
180These are deprecated wrappers around L<BarnOwl::start_edit>, and should not
181be uesd in new code.
182
183=cut
184
185sub start_edit {
186    my %args = (@_);
187    BarnOwl::Internal::start_edit($args{type}, $args{prompt}, $args{callback});
188}
189
190sub start_question {
191    my ($prompt, $callback) = @_;
192    BarnOwl::start_edit(type => 'question', prompt => $prompt, callback => sub {
193            my ($text, $success) = @_;
194            $callback->($text) if $success;
195        });
196}
197
198sub start_password {
199    my ($prompt, $callback) = @_;
200    BarnOwl::start_edit(type => 'password', prompt => $prompt, callback => sub {
201            my ($text, $success) = @_;
202            $callback->($text) if $success;
203        });
204}
205
206sub start_edit_win {
207    my ($prompt, $callback) = @_;
208    BarnOwl::start_edit(type => 'edit_win', prompt => $prompt, callback => sub {
209            my ($text, $success) = @_;
210            $callback->($text) if $success;
211        });
212}
213
214=head2 get_data_dir
215
216Returns the BarnOwl system data directory, where system libraries and
217modules are stored
218
219=head2 get_config_dir
220
221Returns the BarnOwl user configuration directory, where user modules
222and configuration are stored (by default, C<$HOME/.owl>)
223
224=head2 popless_text TEXT
225
226Show a popup window containing the given C<TEXT>
227
228=head2 popless_ztext TEXT
229
230Show a popup window containing the provided zephyr-formatted C<TEXT>
231
232=head2 error STRING
233
234Reports an error and log it in `show errors'. Note that in any
235callback or hook called in perl code from BarnOwl, a C<die> will be
236caught and passed to C<error>.
237
238=head2 debug STRING
239
240Logs a debugging message to BarnOwl's debug log
241
242=head2 getnumcolors
243
244Returns the number of colors this BarnOwl is capable of displaying
245
246=head2 message_matches_filter MESSAGE FILTER_NAME [QUIET = 0]
247
248Returns 1 if C<FILTER_NAME> is the name of a valid filter, and
249C<MESSAGE> matches that filter.  Returns 0 otherwise.  If
250C<QUIET> is false, this method displays an error message if
251if C<FILTER_NAME> does not name a valid filter.
252
253=head2 get_variable_info VARIABLE_NAME
254
255Returns a hash with the following keys, describing the variable named:
256
257=over
258
259=item name
260
261=item description
262
263=item summary
264
265=item validsettings
266
267=item takes_on_off
268
269=back
270
271Fails if C<VARIABLE_NAME> does not name a valid variable.
272
273=head2 add_dispatch FD CALLBACK
274
275Adds a file descriptor to C<BarnOwl>'s internal C<select()>
276loop. C<CALLBACK> will be invoked whenever data is available to be
277read from C<FD>.
278
279C<add_dispatch> has been deprecated in favor of C<AnyEvent>, and is
280now a wrapper for C<add_io_dispatch> called with C<mode> set to
281C<'r'>.
282
283=cut
284
285sub add_dispatch {
286    my $fd = shift;
287    my $cb = shift;
288    add_io_dispatch($fd, 'r', $cb);
289}
290
291=head2 remove_dispatch FD
292
293Remove a file descriptor previously registered via C<add_dispatch>
294
295C<remove_dispatch> has been deprecated in favor of C<AnyEvent>.
296
297=cut
298
299*remove_dispatch = \&remove_io_dispatch;
300
301=head2 add_io_dispatch FD MODE CB
302
303Adds a file descriptor to C<BarnOwl>'s internal C<select()>
304loop. <MODE> can be 'r', 'w', or 'rw'. C<CALLBACK> will be invoked
305whenever C<FD> becomes ready, as specified by <MODE>.
306
307Only one callback can be registered per FD. If a new callback is
308registered, the old one is removed.
309
310C<add_io_dispatch> has been deprecated in favor of C<AnyEvent>.
311
312=cut
313
314our %_io_dispatches;
315
316sub add_io_dispatch {
317    my $fd = shift;
318    my $modeStr = shift;
319    my $cb = shift;
320    my @modes;
321
322    push @modes, 'r' if $modeStr =~ /r/i; # Read
323    push @modes, 'w' if $modeStr =~ /w/i; # Write
324    if (@modes) {
325        BarnOwl::remove_io_dispatch($fd);
326        for my $mode (@modes) {
327            push @{$_io_dispatches{$fd}}, AnyEvent->io(fh => $fd,
328                                                       poll => $mode,
329                                                       cb => $cb);
330        }
331    } else {
332        die("Invalid I/O Dispatch mode: $modeStr");
333    }
334}
335
336=head2 remove_io_dispatch FD
337
338Remove a file descriptor previously registered via C<add_io_dispatch>
339
340C<remove_io_dispatch> has been deprecated in favor of C<AnyEvent>.
341
342=cut
343
344sub remove_io_dispatch {
345    my $fd = shift;
346    undef $_ foreach @{$_io_dispatches{$fd}};
347    delete $_io_dispatches{$fd};
348}
349
350=head2 create_style NAME OBJECT
351
352Creates a new BarnOwl style with the given NAME defined by the given
353object. The object must have a C<description> method which returns a
354string description of the style, and a and C<format_message> method
355which accepts a C<BarnOwl::Message> object and returns a string that
356is the result of formatting the message for display.
357
358=head2 redisplay
359
360Redraw all of the messages on screen. This is useful if you've just
361changed how a style renders messages.
362
363=cut
364
365# perlconfig.c will set this to the value of the -c command-line
366# switch, if present.
367our $configfile;
368
369our @all_commands;
370
371if(!$configfile) {
372    if (-f get_config_dir() . "/init.pl") {
373        $configfile = get_config_dir() . "/init.pl";
374    } elsif (-f $ENV{HOME} . "/.barnowlconf") {
375        $configfile = $ENV{HOME} . "/.barnowlconf";
376    } else {
377        $configfile = $ENV{HOME}."/.owlconf";
378    }
379}
380
381# populate global variable space for legacy owlconf files
382sub _receive_msg_legacy_wrap {
383    my ($m) = @_;
384    $m->legacy_populate_global();
385    return &BarnOwl::Hooks::_receive_msg($m);
386}
387
388=head2 new_command NAME FUNC [{ARGS}]
389
390Add a new owl command. When owl executes the command NAME, FUNC will
391be called with the arguments passed to the command, with NAME as the
392first argument.
393
394ARGS should be a hashref containing any or all of C<summary>,
395C<usage>, or C<description> keys:
396
397=over 4
398
399=item summary
400
401A one-line summary of the purpose of the command
402
403=item usage
404
405A one-line usage synopsis, showing available options and syntax
406
407=item description
408
409A longer description of the syntax and semantics of the command,
410explaining usage and options
411
412=back
413
414=cut
415
416sub new_command {
417    my $name = shift;
418    my $func = shift;
419    my $args = shift || {};
420    my %args = (
421        summary     => "",
422        usage       => "",
423        description => "",
424        %{$args}
425    );
426
427    BarnOwl::Internal::new_command($name, $func, $args{summary}, $args{usage}, $args{description});
428}
429
430=head2 new_variable_int NAME [{ARGS}]
431
432=head2 new_variable_bool NAME [{ARGS}]
433
434=head2 new_variable_string NAME [{ARGS}]
435
436=head2 new_variable_enum NAME [{ARGS}]
437
438Add a new owl variable, either an int, a bool, a string, or an enum with the
439specified name.
440
441For new_variable_enum, ARGS is required to contain a validsettings key pointing
442to an array reference. For all four, it can optionally contain the following
443keys:
444
445=over 4
446
447=item default
448
449The default and initial value for the variable
450
451=item summary
452
453A one-line summary of the variable's purpose
454
455=item description
456
457A longer description of the function of the variable
458
459=back
460
461In addition, new_variable_string optionally accepts a string validsettings
462parameter, in case people want to set it to "<path>".
463
464=cut
465
466sub new_variable_int {
467    my ($name, $args) = @_;
468    my $storage = defined($args->{default}) ? $args->{default} : 0;
469    BarnOwl::new_variable_full($name, {
470            %{$args},
471            get_tostring => sub { "$storage" },
472            set_fromstring => sub {
473                die "Expected integer" unless $_[0] =~ /^-?[0-9]+$/;
474                $storage = 0 + $_[0];
475            },
476            validsettings => "<int>",
477            takes_on_off => 0,
478        });
479}
480
481sub new_variable_bool {
482    my ($name, $args) = @_;
483    my $storage = defined($args->{default}) ? $args->{default} : 0;
484    BarnOwl::new_variable_full($name, {
485            %{$args},
486            get_tostring => sub { $storage ? "on" : "off" },
487            set_fromstring => sub {
488                die "Valid settings are on/off" unless $_[0] eq "on" || $_[0] eq "off";
489                $storage = $_[0] eq "on";
490            },
491            validsettings => "on,off",
492            takes_on_off => 1,
493        });
494}
495
496sub new_variable_string {
497    my ($name, $args) = @_;
498    my $storage = defined($args->{default}) ? $args->{default} : "";
499    BarnOwl::new_variable_full($name, {
500            # Allow people to override this one if they /reaaally/ want to for
501            # some reason. Though we still reserve the right to interpret this
502            # value in interesting ways for tab-completion purposes.
503            validsettings => "<string>",
504            %{$args},
505            get_tostring => sub { $storage },
506            set_fromstring => sub { $storage = $_[0]; },
507            takes_on_off => 0,
508        });
509}
510
511sub new_variable_enum {
512    my ($name, $args) = @_;
513
514    # Gather the valid settings.
515    die "validsettings is required" unless defined($args->{validsettings});
516    my %valid;
517    map { $valid{$_} = 1 } @{$args->{validsettings}};
518
519    my $storage = (defined($args->{default}) ?
520                   $args->{default} :
521                   $args->{validsettings}->[0]);
522    BarnOwl::new_variable_full($name, {
523            %{$args},
524            get_tostring => sub { $storage },
525            set_fromstring => sub {
526                die "Invalid input" unless $valid{$_[0]};
527                $storage = $_[0];
528            },
529            validsettings => join(",", @{$args->{validsettings}})
530        });
531}
532
533=head2 new_variable_full NAME {ARGS}
534
535Create a variable, in full generality. The keyword arguments have types below:
536
537 get_tostring : ()  -> string
538 set_fromstring : string -> int
539 -- optional --
540 summary : string
541 description : string
542 validsettings : string
543 takes_on_off : int
544
545The get/set functions are required. Note that the caller manages storage for the
546variable. get_tostring/set_fromstring both convert AND store the value.
547set_fromstring dies on failure.
548
549If the variable takes parameters 'on' and 'off' (i.e. is boolean-looking), set
550takes_on_off to 1. This makes :set VAR and :unset VAR work. set_fromstring will
551be called with those arguments.
552
553=cut
554
555sub new_variable_full {
556    my $name = shift;
557    my $args = shift || {};
558    my %args = (
559        summary => "",
560        description => "",
561        takes_on_off => 0,
562        validsettings => "<string>",
563        %{$args});
564
565    die "get_tostring required" unless $args{get_tostring};
566    die "set_fromstring required" unless $args{set_fromstring};
567
568    # Strip off the bogus dummy argument. Aargh perl-Glib.
569    my $get_tostring_fn = sub { $args{get_tostring}->() };
570    my $set_fromstring_fn = sub {
571      my ($dummy, $val) = @_;
572      # Translate from user-supplied die-on-failure callback to expected
573      # non-zero on error. Less of a nuisance than interacting with ERRSV.
574      eval { $args{set_fromstring}->($val) };
575      # TODO: Consider changing B::I::new_variable to expect string|NULL with
576      # string as the error message. That can then be translated to a GError in
577      # owl_variable_set_fromstring. For now the string is ignored.
578      return ($@ ? -1 : 0);
579    };
580
581    BarnOwl::Internal::new_variable($name, $args{summary}, $args{description}, $args{validsettings},
582                                    $args{takes_on_off}, $get_tostring_fn, $set_fromstring_fn, undef);
583}
584
585=head2 quote LIST
586
587Quotes each of the strings in LIST and returns a string that will be
588correctly decoded to LIST by the BarnOwl command parser.  For example:
589
590    quote('zwrite', 'andersk', '-m', 'Hello, world!')
591    # returns "zwrite andersk -m 'Hello, world!'"
592
593=cut
594
595sub quote {
596    my @quoted;
597    for my $str (@_) {
598        if ($str eq '') {
599            push @quoted, "''";
600        } elsif ($str !~ /['" \n\t]/) {
601            push @quoted, "$str";
602        } elsif ($str !~ /'/) {
603            push @quoted, "'$str'";
604        } else {
605            (my $qstr = $str) =~ s/"/"'"'"/g;
606            push @quoted, '"' . $qstr . '"';
607        }
608    }
609    return join(' ', @quoted);
610}
611
612=head2 Modify filters by appending text
613
614=cut
615
616sub register_builtin_commands {
617    # Filter modification
618    BarnOwl::new_command("filterappend",
619                         sub { filter_append_helper('appending', '', @_); },
620                       {
621                           summary => "append '<text>' to filter",
622                           usage => "filterappend <filter> <text>",
623                       });
624
625    BarnOwl::new_command("filterand",
626                         sub { filter_append_helper('and-ing', 'and', @_); },
627                       {
628                           summary => "append 'and <text>' to filter",
629                           usage => "filterand <filter> <text>",
630                       });
631
632    BarnOwl::new_command("filteror",
633                         sub { filter_append_helper('or-ing', 'or', @_); },
634                       {
635                           summary => "append 'or <text>' to filter",
636                           usage => "filteror <filter> <text>",
637                       });
638
639    # Date formatting
640    BarnOwl::new_command("showdate",
641                         sub { BarnOwl::time_format('showdate', '%Y-%m-%d %H:%M'); },
642                       {
643                           summary => "Show date in timestamps for supporting styles.",
644                           usage => "showdate",
645                       });
646
647    BarnOwl::new_command("hidedate",
648                         sub { BarnOwl::time_format('hidedate', '%H:%M'); },
649                       {
650                           summary => "Don't show date in timestamps for supporting styles.",
651                           usage => "hidedate",
652                       });
653
654    BarnOwl::new_command("timeformat",
655                         \&BarnOwl::time_format,
656                       {
657                           summary => "Set the format for timestamps and re-display messages",
658                           usage => "timeformat <format>",
659                       });
660
661    # Receive window scrolling
662    BarnOwl::new_command("recv:shiftleft",
663                        \&BarnOwl::recv_shift_left,
664                        {
665                            summary => "scrolls receive window to the left",
666                            usage => "recv:shiftleft [<amount>]",
667                            description => <<END_DESCR
668By default, scroll left by 10 columns. Passing no arguments or 0 activates this default behavior.
669Otherwise, scroll by the number of columns specified as the argument.
670END_DESCR
671                        });
672
673    BarnOwl::new_command("recv:shiftright",
674                        \&BarnOwl::recv_shift_right,
675                        {
676                            summary => "scrolls receive window to the right",
677                            usage => "recv:shiftright [<amount>]",
678                            description => <<END_DESCR
679By default, scroll right by 10 columns. Passing no arguments or 0 activates this default behavior.
680Otherwise, scroll by the number of columns specified as the argument.
681END_DESCR
682                        });
683
684}
685
686$BarnOwl::Hooks::startup->add("BarnOwl::register_builtin_commands");
687
688=head3 filter_append_helper ACTION SEP FUNC FILTER APPEND_TEXT
689
690Helper to append to filters.
691
692=cut
693
694sub filter_append_helper
695{
696    my $action = shift;
697    my $sep = shift;
698    my $func = shift;
699    my $filter = shift;
700    my @append = @_;
701    my $oldfilter = BarnOwl::getfilter($filter);
702    chomp $oldfilter;
703    my $newfilter = "$oldfilter $sep " . quote(@append);
704    my $msgtext = "To filter " . quote($filter) . " $action\n" . quote(@append) . "\nto get\n$newfilter";
705    if (BarnOwl::getvar('showfilterchange') eq 'on') {
706        BarnOwl::admin_message("Filter", $msgtext);
707    }
708    set_filter($filter, $newfilter);
709    return;
710}
711BarnOwl::new_variable_bool("showfilterchange",
712                           { default => 1,
713                             summary => 'Show modifications to filters by filterappend and friends.'});
714
715sub set_filter
716{
717    my $filtername = shift;
718    my $filtertext = shift;
719    my $cmd = 'filter ' . BarnOwl::quote($filtername) . ' ' . $filtertext;
720    BarnOwl::command($cmd);
721}
722
723=head3 time_format FORMAT
724
725Set the format for displaying times (variable timeformat) and redisplay
726messages.
727
728=cut
729
730my $timeformat = '%H:%M';
731
732sub time_format
733{
734    my $function = shift;
735    my $format = shift;
736    if(!$format)
737    {
738        return $timeformat;
739    }
740    if(shift)
741    {
742        return "Wrong number of arguments for command";
743    }
744    $timeformat = $format;
745    redisplay();
746}
747
748=head3 Receive window scrolling
749
750Permit scrolling the receive window left or right by arbitrary
751amounts (with a default of 10 characters).
752
753=cut
754
755sub recv_shift_left
756{
757    my $func = shift;
758    my $delta = shift;
759    $delta = 10 unless defined($delta) && int($delta) > 0;
760    my $shift = BarnOwl::recv_getshift();
761    if($shift > 0) {
762        BarnOwl::recv_setshift(max(0, $shift-$delta));
763    } else {
764        return "Already full left";
765    }
766}
767
768sub recv_shift_right
769{
770    my $func = shift;
771    my $delta = shift;
772    $delta = 10 unless defined($delta) && int($delta) > 0;
773    my $shift = BarnOwl::recv_getshift();
774    BarnOwl::recv_setshift($shift+$delta);
775}
776
777=head3 default_zephyr_signature
778
779Compute the default zephyr signature.
780
781=cut
782
783sub default_zephyr_signature
784{
785  my $zsig = getvar('zsig');
786  if (!defined($zsig) || $zsig eq '') {
787      my $zsigproc = getvar('zsigproc');
788      if (defined($zsigproc) && $zsigproc ne '') {
789          $zsig = `$zsigproc`;
790      } elsif (!defined($zsig = get_zephyr_variable('zwrite-signature'))) {
791          $zsig = ((getpwuid($<))[6]);
792          $zsig =~ s/,.*//;
793      }
794  }
795  chomp($zsig);
796  return $zsig;
797}
798
799=head3 random_zephyr_signature
800
801Retrieve a random line from ~/.zsigs (except those beginning with '#')
802and use it as the zephyr signature.
803
804=cut
805
806sub random_zephyr_signature
807{
808    my $zsigfile = "$ENV{'HOME'}/.zsigs";
809    open my $file, '<', $zsigfile or die "Error opening file $zsigfile: $!";
810    my @lines = grep !(/^#/ || /^\s*$/), <$file>;
811    close $file;
812    return '' if !@lines;
813    my $zsig = "$lines[int(rand(scalar @lines))]";
814    chomp $zsig;
815    return $zsig;
816}
817
818=head3 register_idle_watcher %ARGS
819
820Call a callback whenever the amount of time the user becomes idle or comes
821back from being idle.
822
823You must include the following parameters:
824
825=over 4
826
827=item name
828
829The name given to the idle watcher
830
831=item after
832
833How long the user must be idle, in seconds, before the callback is called.
834If the value is too small, you may have spurious or inaccurate calls.
835(The current lower limit is about 1 second.)
836
837=item callback
838
839The Perl subroutine that gets called when the user has been idle for C<AFTER>
840seconds, or comes back from being idle.  The subroutine is passed one parameter,
841which is true if the user is currently idle, and false otherwise.
842
843=back
844
845This method returns a unique identifier which may be passed to
846L<BarnOwl::unregister_idle_watcher>.
847
848=cut
849
850=head3 unregister_idle_watcher UNIQUE_ID [...]
851
852Removed and returns the idle watcher specified by C<UNIQUE_ID>.
853You may specify multiple unique ids.
854
855=cut
856
857my %idle_watchers;
858tie %idle_watchers, 'Tie::RefHash';
859
860$BarnOwl::Hooks::wakeup->add(sub {
861        foreach my $idle_watcher (values %idle_watchers) {
862            _wakeup_idle_watcher($idle_watcher);
863        }
864    });
865
866sub _wakeup_idle_watcher {
867    my ($idle_watcher, $offset) = @_;
868    $offset = 0 unless defined $offset;
869    # go unidle
870    $idle_watcher->{idle_timer}->stop if $idle_watcher->{idle_timer};
871    undef $idle_watcher->{idle_timer};
872    $idle_watcher->{callback}->(0) if $idle_watcher->{is_idle};
873    $idle_watcher->{is_idle} = 0;
874
875    # queue going idle
876    $idle_watcher->{idle_timer} = BarnOwl::Timer->new({
877        name  => $idle_watcher->{name},
878        after => $idle_watcher->{after} - $offset,
879        cb    => sub {
880            $idle_watcher->{is_idle} = 1;
881            $idle_watcher->{callback}->(1);
882        }
883    });
884}
885
886sub register_idle_watcher {
887    my %args = (@_);
888    $idle_watchers{\%args} = \%args;
889    _wakeup_idle_watcher(\%args, BarnOwl::getidletime); # make sure to queue up the idle/unidle events from this idle watcher
890    return \%args;
891}
892
893sub unregister_idle_watcher {
894    my ($id) = @_;
895    $idle_watchers{$id}->{idle_timer}->stop if $idle_watchers{$id}->{idle_timer};
896    return delete $idle_watchers{$id};
897}
898
899# Stub for owl::startup / BarnOwl::startup, so it isn't bound to the
900# startup command. This may be redefined in a user's configfile.
901sub startup
902{
903}
904
9051;
Note: See TracBrowser for help on using the repository browser.