Jitterbug no more.
[fvwm.git] / modules / FvwmPerl / FvwmPerl.in
blob94e6c9d38adc1448ea5d53b924dbbe535f6d793b
1 #!@PERL@ -w
3 # Copyright (C) 2002-2009 Mikhael Goikhman <migo@cpan.org>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 # Filter this script to pod2man to get a man page:
20 #   pod2man -c "Fvwm Module" FvwmPerl | nroff -man | less -e
22 require 5.004;
23 use strict;
25 BEGIN {
26         use vars qw($prefix $datarootdir $datadir);
27         $prefix = "@prefix@";
28         $datarootdir = "@datarootdir@";
29         $datadir = "@datadir@";
32 use lib "@FVWM_PERLLIBDIR@";
33 use FVWM::Module;
34 use General::FileSystem "-quiet";
35 use General::Parse;
36 use Getopt::Long;
38 # ----------------------------------------------------------------------------
39 # variables
41 my $line_to_eval = undef;
42 my $file_to_load = undef;
43 my $preprocess = 0;
44 my $export_func_names = undef;
45 # whether continue running after --eval, --load or --preprocess, default is no
46 my $stay = 0;
47 my $nolock = 0;
48 my $debug = 0;
49 my $detached = 0;
50 my $pp_args = undef;
51 my $preprocess_options = undef;
52 my $pp_file_count = 0;
53 my $pp_main_quote_ref = undef;
55 sub init_preprocess_vars () {
56         $pp_args = {};
57         $pp_args->{quote} = $$pp_main_quote_ref if $pp_main_quote_ref;
58         $pp_main_quote_ref = \$pp_args->{quote} unless $pp_main_quote_ref;
60         $preprocess_options = {
61                 "c|cmd|command" => \$pp_args->{command},
62                 "q|quote=s"     => \$pp_args->{quote},
63                 "w|winid=s"     => \$pp_args->{winid},
64                 "nosend"        => \$pp_args->{nosend},
65                 "noremove"      => \$pp_args->{noremove},
66         };
69 init_preprocess_vars();
71 my $options = {
72         "e|eval=s"     => \$line_to_eval,
73         "l|load=s"     => \$file_to_load,
74         "p|preprocess" => \$preprocess,
75         "x|export:s"   => \$export_func_names,
76         "s|stay!"      => \$stay,
77         "nolock"       => \$nolock,
78         "debug=i"      => \$debug,
79         %$preprocess_options,
82 my $module = new FVWM::Module(
83         Name          => "FvwmPerl",
84         Mask          => M_STRING,
85         SyncMask      => M_STRING,
86         EnableOptions => $options,
87         EnableAlias   => 1,
88         Debug         => \$debug,  # $debug is not really ready yet
91 sub print_action_error ($$) {
92         my $action = shift;
93         my $err_msg = shift;
94         return if $err_msg =~ /^!/;
95         $err_msg =~ s/\s+$//s;
96         print STDERR "[", $module->name, "][$action]: $err_msg\n";
99 # ----------------------------------------------------------------------------
100 # prepare the environment that may be used in the sent perl commands
102 my $version = "@VERSION@";
104 my ($a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p)
105         = ("", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "");
106 my (@a, @b, @c, @d, @e, @f, @g, @h, @i, @j, @k, @l, @m, @n, @o, @p);
107 my (%a, %b, %c, %d, %e, %f, %g, %h, %i, %j, %k, %l, %m, %n, %o, %p);
109 sub cmd ($;$) {
110         my $command = shift;
111         my $win_id = shift;
112         $module->send($command, $win_id);
115 *command = \*cmd; *command = \*command;  # alias
117 sub stop () {
118         # send a signal to the event loop to terminate the module
119         $module->terminate;
122 sub skip () {
123         # send a signal to the event loop to terminate the current event handler
124         $module->terminate("continue");
127 sub unlock () {
128         # enable asynchronous evaluation
129         $module->send_unlock;
132 sub detach () {
133         my $pid = fork();
135         # main process skips the remaining evaluation
136         skip() unless defined $pid && $pid == 0;
138         # child process will exit after evaluation
139         $detached = 1;
142 sub show_message ($;$$) {
143         require FVWM::Module::Toolkit;
144         FVWM::Module::Toolkit->show_message(
145                 $_[0], $_[1] || "FvwmPerl user message", $_[2]
146         );
149 sub export ($;$) {
150         my $func_names = shift || "";
151         my $do_unexport = shift || 0;
153         my @func_names = split(/[\s,]+/, $func_names);
154         @func_names = qw(Eval .) if $func_names eq "";
156         my $name = $module->name;
158         foreach (@func_names) {
159                 my $action =
160                         /eval/i? 'eval':
161                         /load/i? 'load':
162                         /preprocess|pp/i || $_ eq "."? 'preprocess -c --':
163                         die "Can't guess action for function '$_' to export\n";
165                 $module->send(qq(
166                         DestroyFunc $_
167                 ) . ($do_unexport ? "" : qq(
168                         AddToFunc $_ I SendToModule $name $action \$*
169                 )));
170         }
173 sub load ($) {
174         my $filename = shift;
175         my $contents = load_file($filename);
176         if (!defined $contents) {
177                 print_action_error("load", "Can't find and read $filename: $!");
178                 return;
179         }
180         eval $$contents;
181         print_action_error("load", "$@") if $@;
184 sub do_eval ($) {
185         my $string = shift;
186         eval $string;
187         print_action_error("eval", "$@") if $@;
188         if ($detached) {
189                 # let's hope we should not clean-up anything
190                 exit(0);
191         }
194 sub preprocess_directives ($;$) {
195         my $text_ref = shift;
196         my $depth = shift || 0;
198         my $quote = $PreprocessNamespace::PPP_QUOTE1;
199         my $processed_text = "";
201         my $error_sub = sub ($) {
202                 print_action_error("preprocess", "$_[0], preprocessing failed");
203         };
204         my ($start, $directive, $params, $end);
206         while ($$text_ref =~ m{\A(.*?)^$quote(\w+)[ \t]*(.*?)\n(.*)\z}ms) {
207                 ($start, $directive, $params, $end) = ($1, $2, $3, $4);
208                 $$text_ref = "";
209                 #print "\t$depth $directive $params\n";
211                 if (eqi($directive, "End")) {
212                         if ($depth == 0) {
213                                 $error_sub->("Unexpected ${quote}End");
214                                 return undef;
215                         }
216                         $$text_ref = $processed_text . $start;
217                         return $end;
218                 }
220                 my $subtext = $end;
222                 if (eqi($directive, "Repeat")) {
223                         my $count = get_token($params);
224                         unless (defined $count && $count =~ /^\d+$/) {
225                                 $error_sub->("Usage: ${quote}Repeat count");
226                                 return undef;
227                         }
228                         $end = &preprocess_directives(\$subtext, $depth + 1);
229                         return undef unless defined $end;
230                         $start .= $subtext x $count;
231                         next;
232                 }
233                 my $prefix = undef;
234                 if (eqi($directive, "ModuleConfig")) {
235                         my ($module_name, $destroy) = get_tokens($params, 2);
236                         unless (defined $module_name) {
237                                 $error_sub->("Usage: ${quote}ModuleConfig module-name");
238                                 return undef;
239                         }
240                         if (defined $destroy && eqi($destroy, "destroy")) {
241                                 $start .= "DestroyModuleConfig $module_name: *\n";
242                         };
243                         $prefix = "*$module_name: ";
244                 }
245                 if (defined $prefix || eqi($directive, "Prefix")) {
246                         $prefix = get_token($params) unless defined $prefix;
247                         unless (defined $prefix) {
248                                 $error_sub->("Usage: ${quote}Prefix prefix");
249                                 return undef;
250                         }
251                         $end = &preprocess_directives(\$subtext, $depth + 1);
252                         return undef unless defined $end;
253                         foreach (split(/\n/s, $subtext)) {
254                                 $start .= "$prefix$_\n" unless /^\s*$/;
255                         }
256                         next;
257                 }
258         } continue {
259                 $processed_text .= $start;
260                 $$text_ref = $end;
261         }
263         if ($depth == 0) {
264                 $$text_ref = $processed_text . $$text_ref if $processed_text ne "";
265                 return "";
266         }
267         $error_sub->("No corresponding ${quote}End found");
268         return undef;
271 sub preprocess ($;$) {
272         my $args = shift;
273         my $data = shift;
275         my $nosend   = $args->{nosend};
276         my $noremove = $args->{noremove};
277         my $command  = $args->{command};
278         my $quote    = $args->{quote} || '%';
279         my $winid    = $args->{winid} || undef;
281         my ($quote1, $quote2) = split(//, $quote, 2);
282         $quote2 ||= $quote1;
283         $winid = eval $winid if $winid && $winid =~ /^0(x[\da-f]+|[0-7]+)$/;
285         unlock() unless $command;
287         my $depth = $args->{depth};
288         $depth ||= 0;
289         if ($depth > 20) {
290                 print_action_error("preprocess", "Too deep include depth=$depth");
291                 return;
292         }
294         my $text_ref = $command? \$data: load_file($data);
295         unless (defined $text_ref) {
296                 print_action_error("preprocess", "No file to preprocess ($data)");
297                 return;
298         }
300         # there should be another way without running external programs
301         my @dimentions = `xdpyinfo | grep dimensions` =~ /(\d+)x(\d+)/;
303         {
304                 package PreprocessNamespace;
305                 no strict "vars";
306                 # OR-ing is a work around for "used once" warning
308                 $PPP_DEPTH    = $depth;
309                 $PPP_QUOTE    = $quote;
310                 $PPP_QUOTE1   = $quote1;
311                 $PPP_QUOTE2   = $PPP_QUOTE2 || $quote2;
312                 $PPP_NOSEND   = $nosend;
313                 $PPP_NOREMOVE = $noremove;
314                 $USER    = $USER    || $ENV{USER};
315                 $DISPLAY = $DISPLAY || $ENV{DISPLAY};
316                 $WIDTH   = $WIDTH   || $dimentions[0];
317                 $HEIGHT  = $HEIGHT  || $dimentions[1];
318                 $FVWM_VERSION = $FVWM_VERSION || $version;
319                 $FVWM_MODULEDIR = $FVWM_MODULEDIR || $ENV{FVWM_MODULEDIR};
320                 $FVWM_DATADIR = $FVWM_DATADIR || $module->site_data_dir;
321                 $FVWM_USERDIR = $FVWM_USERDIR || $module->user_data_dir;
322         }
324         # perl code substitution first
325         $$text_ref =~ s/\Q$quote1\E { ( .*? ) } \Q$quote2\E/
326                 my $result = eval "
327                         no strict;
328                         package PreprocessNamespace;
329                         $1
330                 ";
331                 if ($@) {
332                         print_action_error("preprocess", $@);
333                         $result = "";
334                 }
335                 $result;
336         /sgex;
338         # line based directives
339         preprocess_directives($text_ref);
341         if ($command) {
342                 $module->send($$text_ref, $winid);
343                 return;
344         }
346         my $temp_filename = $module->user_data_dir . "/.FvwmPerl-preprocess-$$";
347         $temp_filename .= "-" . (++$pp_file_count);
348         save_file($temp_filename, $text_ref);
350         unless ($nosend) {
351                 $module->send("Read $temp_filename", $winid);
352                 $module->send("Exec rm -f '$temp_filename'")
353                         unless $noremove;
354         }
357 sub PreprocessNamespace::include ($) {
358         my $file = shift;
359         ::preprocess({
360                 depth    => $PreprocessNamespace::PPP_DEPTH + 1,
361                 quote    => $PreprocessNamespace::PPP_QUOTE,
362                 nosend   => $PreprocessNamespace::PPP_NOSEND,
363                 noremove => $PreprocessNamespace::PPP_NOREMOVE,
364         }, $file);
365         return "";
368 # ----------------------------------------------------------------------------
369 # event handlers
371 sub process_message ($$) {
372         my $event = $_[1];
373         my $string = $event->_text;
375         $string =~ s/^\s+//;
376         return if $string eq "";
377         my ($action, $rest) = split(/\s+/, $string, 2);
378         $action = lc($action);
380         if ($action eq "eval") {
381                 return unless defined $rest;
382                 do_eval($rest);
383         }
385         elsif ($action eq "load") {
386                 return unless defined $rest;
387                 load(get_token($rest));
388         }
390         elsif ($action eq "preprocess") {
391                 @ARGV = split(/ /, $rest);
392                 init_preprocess_vars();
393                 my $parser = new Getopt::Long::Parser(
394                         config => [qw(pass_through require_order)]
395                 );
396                 $parser->getoptions(%$preprocess_options) || return;
397                 $pp_args->{winid} = $event->_win_id || undef
398                         unless defined $pp_args->{winid} && $pp_args->{winid} =~ /^\d/;
400                 preprocess($pp_args, join(" ", @ARGV));
401         }
403         elsif ($action eq "export") {
404                 export($rest);
405         }
407         elsif ($action eq "unexport") {
408                 export($rest, 1);
409         }
411         elsif ($action eq "stop") {
412                 stop();
413         }
415         elsif ($action eq "dump") {
416                 # will dump non-void variables in the future
417         }
419         else {
420                 print_action_error("process_message", "Unknown action ($action)");
421         }
424 $module->add_handler(M_STRING, \&process_message);
426 # ----------------------------------------------------------------------------
427 # execution
429 # unlock fvwm earlier if requested
430 $module->send_ready if $nolock;
432 if (defined $export_func_names) {
433         export($export_func_names);
434         $stay = 1;
437 if (defined $line_to_eval) {
438         do_eval($line_to_eval);
439         exit(0) unless $stay;
442 if (defined $file_to_load) {
443         load($file_to_load);
444         exit(0) unless $stay;
447 if ($preprocess) {
448         preprocess($pp_args, join(" ", @ARGV));
449         exit(0) unless $stay;
452 $module->event_loop;
454 __END__
456 # ----------------------------------------------------------------------------
457 # man page
459 =head1 NAME
461 FvwmPerl - the fvwm perl manipulator and preprocessor
463 =head1 SYNOPSIS
465 FvwmPerl should be spawned by fvwm(1) for normal functionality.
467 To run this module, place this command somewhere in the configuration:
469     Module FvwmPerl [params]
473     ModuleSynchronize FvwmPerl [params]
475 if you want to immediately start to send commands to FvwmPerl.
477 =head1 DESCRIPTION
479 This module is intended to extend fvwm commands with the perl scripting
480 power.  It enables to embed perl expressions in the fvwm config files and
481 construct fvwm commands.
483 =head1 INVOCATION
485 If you want to invoke the unique and persistent instanse of FvwmPerl, it is
486 suggested to do this from the I<StartFunction>.  Calling it from the top is
487 also possible, but involves some issues not discussed here.
489     AddToFunc StartFunction I Module FvwmPerl
491 There are several command line switches:
493 B<FvwmPerl>
494 [ B<--eval> line ]
495 [ B<--load> file ]
496 [ B<--preprocess> [ B<--quote> char ] [ B<--winid> wid ] [ B<--cmd> ]
497 [ B<--nosend> ] [ B<--noremove> ] [ line | file ] ]
498 [ B<--export> [names] ]
499 [ B<--stay> ]
500 [ B<--nolock> ]
501 [ alias ]
503 Long switches may be abbreviated to short one-letter switches.
505 B<-e>|B<--eval> line - evaluate the given perl code
507 B<-l>|B<--load> file - evaluate perl code in the given file
509 B<-p>|B<--preprocess> [ file ] - preprocess the given fvwm config file
511 The following 5 options are only valid together with B<--preprocess>
512 option.
514 B<-c>|B<--cmd> line - an fvwm command to be preprocessed instead of file
516 B<-q>|B<--quote> char - change the default '%' quote
518 B<-w>|B<--winid> wid - set explicit window context (should begin with
519 digit, may be in oct or hex form; this window id overwrites implicit
520 window context if any)
522 B<--nosend> - do not send the preprocessed file to I<fvwm> for B<Read>ing,
523 the default is send. Useful for preprocessing non fvwm config files.
525 B<--noremove> - do not remove the preprocessed file after sending
526 it to I<fvwm> for B<Read>ing, the default is remove. Useful for debugging.
528 B<-x>|B<--export> [names] - define fvwm shortcut functions (by default,
529 two functions named "Eval" and ".").  This option implies B<--stay>.
531 B<-s>|B<--stay> - continues an execution after B<--eval>, B<--load> or
532 B<--preprocess> are processed.  By default, the module is not persistent
533 in this case, i.e. B<--nostay> is assumed.
535 B<--nolock> - when one of the 3 action options is given, this option causes
536 unlocking I<fvwm> immediately. By default the requested action is executed
537 synchronously; this only makes difference when invoked like:
539     ModuleSynchronous FvwmPerl --preprocess someconfig.ppp
541 If B<--nolock> is added here, B<ModuleSynchronous> returns immediately.
542 Note that B<Module> returns immediately regardless of this option.
544 =head1 USING ALIAS
546 Aliases allow to have several module invocations and work separately
547 with all invocations, here is an example:
549     ModuleSynchronous FvwmPerl FvwmPerl-JustTest
550     SendToModule FvwmPerl-JustTest eval $a = 2 + 2; $b = $a
551     SendToModule FvwmPerl-JustTest eval cmd("Echo 2 + 2 = $b")
552     KillModule FvwmPerl FvwmPerl-JustTest
554 =head1 PREPROCESSING EXAMPLE
556 One of the effective proprocessing solutions is to pass the whole fvwm
557 configuration with embeded perl code to "FvwmPerl --preprocess".
558 An alternative approach is to write a perl script that produces fvwm
559 commands and sends them for execution, this script may be loaded using
560 "FvwmPerl --load". There are hovewer intermediate solutions that
561 preprocess only separate configuration lines (or alternatively,
562 execute separate perl commands that produce fvwm commands).
564 The following code snippet adds ability of arithmetics and string scripting
565 to certain lines that need this. To use this, you want to start FvwmPerl as
566 your first command so that other commands may be asked to be preprosessed.
568     ModuleSynchronize FvwmPerl
570     AddToFunc .
571     + I SendToModule FvwmPerl preprocess -c -- $*
573     . Exec exec xterm -name xterm-%{++$i}%   # use unique name
575     . GotoDesk 0 %{ $[desk.n] + 1 }%         # go to next desk
577     . Exec exec %{ -x "/usr/bin/X11/aterm" ? "aterm" : "xterm" }% -sb
579     # center a window
580     Next (MyWindow) . Move \
581       %{($WIDTH - $[w.width]) / 2}%p %{($HEIGHT - $[w.height]) / 2}%p
583     . Exec exec xmessage %{2 + 2}%           # simple calculator
585     . %{main::show_message(2 + 2, "Yet another Calculator"); ""}%
587 =head1 ACTIONS
589 There are several actions that FvwmPerl may perform:
591 =over 4
593 =item B<eval> perl-code
595 Evaluate a line of perl code.
597 A special function B<cmd(>"command"B<)> may be used in perl code to send
598 commands back to fvwm.
600 If perl code contains an error, it is printed to the standard error stream
601 with the I<[FvwmPerl][eval]:> header prepended.
603 =item B<load> file-name
605 Load a file of perl code.
606 If the file is not fully qualified, it is searched in the user
607 directory $FVWM_USERDIR (usually ~/.fvwm) and the system wide
608 data directory $FVWM_DATADIR.
610 A special function B<cmd(>"command"B<)> may be used in perl code to send
611 commands back to fvwm.
613 If perl code contains an error, it is printed to the standard error stream
614 with the I<[FvwmPerl][load]:> header prepended.
616 =item B<preprocess> [-q|--quote char] [-c|--cmd] [I<line> | I<file>]
618 Preprocess fvwm config I<file> or (if --cmd is given) I<line>.
619 This file contains lines that are not touched (usually fvwm commands)
620 and specially preformatted perl code that is processed and replaced.
621 Text enclosed in B<%{> ... B<}%> delimiters, that may start anywhere
622 on the line and end anywhere on the same or an other line, is perl code.
624 The I<quote> parameter changes perl code delimiters.  If a single char
625 is given, like '@', the delimiters are B<@{> ... B<}@>.
626 If the given quote is 2 chars, like B<E<lt>E<gt>>, the quotes are
627 B<E<lt>{> ... B<}E<gt>>
629 The perl code is substituted for the result of its evaluation.
630 I.e. %{$a = "c"; ++$a}% is replaced with "d".
632 The evaluation is unlike B<eval> and B<load> is done under the
633 package PreprocessNamespace and without I<use strict>, so you are
634 free to use any variable names without fear of conflicts. Just don't
635 use uninitialized variables to mean undef or empty list (they may be in fact
636 initialized by the previous preprocess action), and do a clean-up if needed.
637 The variables and function in the I<main> package are still available,
638 like ::cmd() or ::skip(), but it is just not a good idea to access them
639 while preprocessing.
641 There is a special function B<include>(I<file>) that loads a file,
642 preprocesses it and returns the preprocessed result. Avoid recursion.
644 If any embedded perl code contains an error, it is printed to the standard
645 error stream and prepended with the I<[FvwmPerl][preprocess]:> header.
646 The result of substitution is empty in this case.
648 The following variables may be used in the perl code:
650 $USER,
651 $DISPLAY,
652 $WIDTH,
653 $HEIGHT,
654 $FVWM_VERSION,
655 $FVWM_MODULEDIR,
656 $FVWM_DATADIR,
657 $FVWM_USERDIR
659 The following line based directives are recognized when preprocessing.
660 They are processed after the perl code (if any) is substituted.
662 =over 4
664 =item %B<Repeat> I<count>
666 Causes the following lines to be repeated I<count> times.
668 =item %B<ModuleConfig> I<module-name> [ destroy ]
670 Causes the following lines to be interpreted as the given module configuration.
671 If "destroy" is specified the previous module configuration is destroyed first.
673 =item %B<Prefix> I<prefix>
675 Prefixes the following lines with the quoted I<prefix>.
677 =item %B<End> any-optional-comment
679 Ends any of the directives described above, may be nested.
681 =back
683 Examples:
685     %Prefix "AddToFunc SwitchToWindow I"
686         Iconify off
687         WindowShade off
688         Raise
689         WarpToWindow 50 50
690     %End
692     %ModuleConfig FvwmPager destroy
693         Colorset 0
694         Font lucidasans-10
695         DeskTopScale 28
696         MiniIcons
697     %End ModuleConfig FvwmPager
699     %Prefix "All (MyWindowToAnimate) ResizeMove "
700     100 100 %{($WIDTH - 100) / 2}% %{($HEIGHT - 100) / 2}%
701     %Repeat %{$count}%
702     br w+2c w+2c w-1c w-1c
703     %End
704     %Repeat %{$count}%
705     br w-2c w-2c w+1c w+1c
706     %End
707     %End Prefix
709 Additional preprocess parameters --nosend and --noremove may be given too.
710 See their description at the top.
712 =item B<export> [I<func-names>]
714 Send to I<fvwm> the definition of shortcut functions that help to activate
715 different actions of the module (i.e. B<eval>, B<load> and B<preprocess>).
717 Function names (I<func-names>) may be separated by commas or/and whitespace.
718 By default, two functions "Eval" and "." are assumed.
720 The actual action defined in a function is guessed from the function name
721 if possible, where function name "." is reserved for B<preprocess> action.
723 For example, any of these two fvwm commands
725    SendToModule MyPerl export PerlEval,PP
726    FvwmPerl --export PerlEval,PP MyPerl
728 define the following two shortcut functions:
730   DestroyFunc PerlEval
731   AddToFunc I SendToModule MyPerl eval $*
732   DestroyFunc PP
733   AddToFunc I SendToModule MyPerl preprocess -c -- $*
735 =back
737 These 4 actions may be requested in one of 3 ways: 1) in the command line when
738 FvwmPerl is invoked (in this case FvwmPerl is short-lived unless B<--stay>
739 or B<--export> is also given), 2) by sending the corresponding message in
740 fvwm config using SendToModule, 3) by calling the corresponding perl function
741 in perl code.
743 =head1 FUNCTIONS
745 There are several functions that perl code may call:
747 =over 4
749 =item B<cmd(>I<$fvwm_command>B<)>
751 In case of B<eval> or B<load> - send back to fvwm a string I<$fvwm_command>.
752 In case of B<preprocess> - append a string I<$fvwm_command> to the output of
753 the embedded perl code.
755 =item B<do_eval(>I<$perl_code>B<)>
757 This function is equivalent to the B<eval> functionality
758 on the string I<$perl_code>, described above.
760 =item B<load(>I<$filename>B<)>
762 This function is equivalent to the B<load> functionality
763 on the file $filename, described above.
765 =item B<preprocess(>I<@params, ["-c $command"] [$filename]>B<)>
767 This function is equivalent to the B<preprocess> functionality
768 with the given parameters and the file $filename described above.
770 =item B<export(>I<$func_names, [$do_unexport]>B<)>
772 This function is equivalent to the B<export> functionality
773 with the given $func_names, described above. May also B<unexport>
774 the function names if the second parameter is true.
776 Function names should be separated by commas or/and whitespace.
777 If I<$func_names> is empty then functions "Eval" and "." are assumed.
779 =item B<stop()>
781 Terminates the module.
783 =item B<skip()>
785 Skips the rest of the event callback code, i.e. the module returns to listen
786 to new module events.
788 =item B<unlock()>
790 Unsynchronizes the event callback from fvwm. This may be useful to prevent
791 deadlocks, i.e. usually fvwm kills the non-responding module if the event
792 callback is not finished in I<ModuleTimeout> seconds. This prevents it.
794 This example causes FvwmPerl to suspend its execution for one minute:
796     SendModule FvwmPerl eval unlock(); sleep(60);
798 However, verify that there is no way a new message is sent by fvwm while the
799 module is busy, and fvwm stays locked on this new message for too long.
800 See also the B<detach> solution if you need long lasting operations.
802 =item B<detach()>
804 Forks and detaches the rest of the event callback code from the main
805 process. This may be useful to prevent killing the module if its event
806 callback should take a long time to complete and it may be done in the
807 detached child. The detached child may still send commands to fvwm (don't
808 rely on this), but not receive the events of course, it exits immediately
809 after the callback execution is finished.
811 If you use detach(), better only send commands to fvwm in one process (the
812 main one or the detached one), doing otherwise may often cause conflicts.
814 =item B<show_message(>$msg, $title[, $use_stderr_too=1]B<)>
816 Shows a dialog window with the given message, using whichever X tool is
817 found in the system.
819 See B<FVWM::Module::Toolkit>::B<show_message> for more information.
821 =back
823 =head1 VARIABLES
825 There are several global variables in the I<main> namespace that may be used
826 in the perl code:
828     $a, $b, ... $h
829     @a, @b, ... @h
830     %a, %b, ... %h
832 They all are initialized to the empty value and may be used to store a state
833 between different calls to FvwmPerl actions (B<eval> and B<load>).
835 If you need more readable variable names, either write "no strict 'vars';"
836 at the start of every perl code or use a hash for this, like:
838     $h{id} = $h{first_name} . " " . $h{second_name}
840 or use a package name, like:
842     @MyMenu::terminals = qw( xterm rxvt );
843     $MyMenu::item_num = @MyMenu::terminals;
845 There may be a configuration option to turn strictness on and off.
847 =head1 MESSAGES
849 FvwmPerl may receive messages using the fvwm command SendToModule.
850 The names, meanings and parameters of the messages are the same as the
851 corresponding actions, described above.
853 Additionally, a message B<stop> causes a module to quit.
855 A message B<unexport> [I<func-names>] undoes the effect of B<export>,
856 described in the ACTIONS section.
858 A message B<dump> dumps the contents of the changed variables (not yet).
860 =head1 EXAMPLES
862 A simple test:
864     SendToModule FvwmPerl eval $h{dir} = $ENV{HOME}
865     SendToModule FvwmPerl eval load($h{dir} . "/test.fpl")
866     SendToModule FvwmPerl load $[HOME]/test.fpl
867     SendToModule FvwmPerl preprocess config.ppp
868     SendToModule FvwmPerl export Eval,PerlEval,PerlLoad,PerlPP
869     SendToModule FvwmPerl unexport PerlEval,PerlLoad,PerlPP
870     SendToModule FvwmPerl stop
872 The following example handles root backgrounds in fvwmrc.
873 All these commands may be added to StartFunction.
875     Module FvwmPerl --export PerlEval
877     # find all background pixmaps for a later use
878     PerlEval $a = $ENV{HOME} . "/bg"; \
879       opendir DIR, $a; @b = grep { /xpm$/ } readdir(DIR); closedir DIR
881     # build a menu of background pixmaps
882     AddToMenu MyBackgrounds "My Backgrounds" Title
883     PerlEval foreach $b (@b) \
884       { cmd("AddToMenu MyBackgrounds '$b' Exec fvwm-root $a/$b") }
886     # choose a random background to load on start-up
887     PerlEval cmd("AddToFunc \
888       InitFunction + I Exec exec fvwm-root $a/" . $b[int(random(@b))])
890 =head1 ESCAPING
892 B<SendToModule> just like any other fvwm commands expands several dollar
893 prefixed variables.  This may clash with the dollars perl uses.
894 You may avoid this by prefixing SendToModule with a leading dash.
895 The following 2 lines in each pair are equivalent:
897     SendToModule FvwmPerl eval $$d = "$[DISPLAY]"
898     -SendToModule FvwmPerl eval $d = "$ENV{DISPLAY}"
900     SendToModule FvwmPerl eval \
901         cmd("Echo desk=$d, display=$$d")
902     SendToModule FvwmPerl preprocess -c \
903         Echo desk=%("$d")%, display=%{$$d}%
905 Another solution to avoid escaping of special symbols like dollars
906 and backslashes is to create a perl file in ~/.fvwm and then load it:
908     SendToModule FvwmPerl load build-menus.fpl
910 If you need to preprocess one command starting with a dash, you should
911 precede it using "--".
913     # this prints the current desk, i.e. "0"
914     SendToModule FvwmPerl preprocess -c Echo "$%{$a = "c"; ++$a}%"
915     # this prints "$d"
916     SendToModule FvwmPerl preprocess -c -- -Echo "$%{"d"}%"
917     # this prints "$d" (SendToModule expands $$ to $)
918     SendToModule FvwmPerl preprocess -c -- -Echo "$$%{"d"}%"
919     # this prints "$$d"
920     -SendToModule FvwmPerl preprocess -c -- -Echo "$$%{"d"}%"
922 Again, it is suggested to put your command(s) into file and preprocess
923 the file instead.
925 =head1 CAVEATS
927 FvwmPerl being written in perl and dealing with perl, follows the famous
928 perl motto: "There's more than one way to do it", so the choice is yours.
930 Here are more pairs of equivalent lines:
932     Module FvwmPerl --load "my.fpl" --stay
933     Module FvwmPerl -e 'load("my.fpl")' -s
935     SendToModule FvwmPerl preprocess --quote '@' my.ppp
936     SendToModule FvwmPerl eval preprocess({quote => '@'}, "my.ppp");
938 Warning, you may affect the way FvwmPerl works by evaluating appropriate
939 perl code, this is considered a feature not a bug.  But please don't do this,
940 write your own fvwm module in perl instead.
942 =head1 SEE ALSO
944 The fvwm(1) man page describes all available commands.
946 Basically, in your perl code you may use any function or class method from
947 the perl library installed with fvwm, see the man pages of perl packages
948 B<General::FileSystem>, B<General::Parse> and B<FVWM::Module>.
950 =head1 AUTHOR
952 Mikhael Goikhman <migo@homemail.com>.
954 =cut