3 # Copyright (c) 2002-2009 Mikhael Goikhman
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 Utilities" fvwm-perllib | nroff -man | less -e
22 #use strict; # comment to make it faster
25 # use vars qw($prefix $datarootdir $datadir $perllibdir);
27 $datarootdir = "@datarootdir@";
28 $datadir = "@datadir@";
29 $perllibdir = "@FVWM_PERLLIBDIR@";
31 # try to do it as fast as possible
32 if ($ARGV[0] eq 'dir') {
40 use General::FileSystem '-die';
42 my $version = "@VERSION@";
43 my $version_info = "@VERSIONINFO@";
45 my $pager = $ENV{PAGER} || "less -e";
51 "help|h|?" => \&show_help,
52 "version|v|V" => \&show_version,
56 "dir" => sub { print $perllibdir; exit(0); },
59 if ($ARGV[0] eq 'man') {
62 } elsif ($ARGV[0] eq 'cat') {
65 } elsif ($ARGV[0] eq 'raw') {
70 wrong_usage() if !$do_man && !$do_cat && !$do_raw || @ARGV > 1;
72 my $man_or_cat_str = $do_man || $do_raw ? "man" : "cat";
73 my $internal_pods = {};
75 $internal_pods->{index} = qq{
78 index - lists all available help topics
82 Recent I<fvwm> versions install the Perl library that makes creating
83 fvwm modules in Perl possible and easy.
85 You may read the Perl library documentation locally by running:
87 % fvwm-perllib $man_or_cat_str <topic>
98 % fvwm-perllib $man_or_cat_str FVWM::Module
102 Mikhael Goikhman <migo\@homemail.com>.
105 $internal_pods->{tutorial} = q{
108 tutorial - common techniques for writting fvwm modules
112 :head2 What is a window manager
114 A window manager is a program that runs on top of the X Window
115 System and manages windows, menus, key and mouse bindings, virtual
116 desktops and pages, draws window decorations using defined colors or
117 images, title-bar buttons and fonts. The window manager defines
118 window placement and focus policies. It may also manage such things
119 as root background, mouse cursors, sounds, run applications and
120 do other nice things.
122 :head2 What is a module
124 In the unix traditions, different functionality may be implemented
125 by separate programs to reduce a bloat. A module is an optional
126 program that is intended to extend the window manager using a defined
129 Fvwm modules are spawned by the main I<fvwm> executable. They
130 usually listen to the window manager events, do some useful work and
131 send back commands for execution. There are transient modules that
132 exit immediately or shortly, and persistent modules that exit
133 together with a window manager or when a user requests. Some
134 modules may control windows or other modules. Some modules may supply
135 a GUI, others may be non interactive.
137 :head2 Creating a simple module
139 Let's create a module that shows a flash window for one second when
140 you change pages. We will use I<xmessage> with nifty options for our
141 flash purposes, but you may use your fantasy to do this better.
143 First, we should understand when our module works. Usually a module
144 does nothing (sleeps) and is awaken when something interesting
145 happens. This is achieved using events. A module defines events that
146 it is interesting to receive and set-ups event handlers (perl
147 functions) to be called when the event happens. Then a module enters
148 the event loop where it sleeps all the time until one or another
149 event happens. Most of the module work is done in the event
150 handlers. When an event is processed, the module enters the event
153 In our case, we should listen to an fvwm event I<M_NEW_PAGE>. The list
154 of all events may be found in man page "events". When we receive
155 the event we want to get new page coordinates and display them
156 using our special xmessage window.
158 Now, from theory to practice. The header of all modules written in
159 Perl is pretty standard:
163 use lib `fvwm-perllib dir`;
166 Then create the actual module object:
168 my $module = new FVWM::Module(
169 Mask => M_NEW_PAGE | M_NEW_DESK,
173 The B<Debug> option tells to print the event names that a module
174 receives to help writing a module, it also echoes all sent commands.
175 The B<Mask> option tells which events a module wants to receive, in
176 our case these are events generated on the page and desk changes.
178 To handle events, event handlers that are perl functions, should be
179 defined. It is ok not to define any event handler for I<M_NEW_DESK>
180 and to define two event handlers for I<M_NEW_PAGE>. But for our
181 purposes one I<M_NEW_PAGE> would be more than enough:
183 $module->add_handler(M_NEW_PAGE, \&got_new_page);
185 It is a time to implement our C<got_new_page> function that will be
186 called every time the desktop page is changed.
189 my ($module, $event) = @_;
191 my $width = $event->_vp_width;
192 my $height = $event->_vp_height;
194 if (!$width || !$height) {
195 # this may happen when doing DeskTopSize 1x1 on page 2 2
198 my $page_nx = int($event->_vp_x / $width);
199 my $page_ny = int($event->_vp_y / $height);
201 # actually show the flash
202 $module->send("Exec xmessage -name FlashWindow \
203 -bg cyan -fg white -center -timeout 1 -button '' \
204 -xrm '*cursorName: none' -xrm '*borderWidth: 2' \
205 -xrm '*borderColor: yellow' -xrm '*Margin: 12' \
206 '($page_nx, $page_ny)'");
209 All event handlers are called with 2 parameters, a module and an
210 event objects. The arguments for all events are defined in
211 L<FVWM::EventNames>. Each event type has its own arguments. Our
212 I<M_NEW_PAGE> has 5 arguments: vp_x vp_y desk vp_width vp_height.
213 We should do some calculations to get the page numbers from viewport
216 The B<send> method passes the command to I<fvwm> for execution.
217 It would be better to set-up the FlashWindow specially:
219 $module->send("Style FlashWindow StaysOnTop, NoTitle, NoHandles, \
220 BorderWidth 10, WindowListSkip, NeverFocus, UsePPosition");
222 Finally, all persistent modules should enter the event loop:
226 The full module source that we just wrote is available at
227 ftp://ftp.fvwm.org/pub/fvwm/devel/sources/tests/perl/module-flash .
228 To run it execute this fvwm command:
230 Module /path/to/module-flash
232 To kill the module, execute:
234 KillModule /path/to/module-flash
236 :head2 Using event trackers
238 In fact, the task of calculating page coordinates, or managing
239 information about all windows, or gathering colorset, module or
240 global information is so often, that there are existing
241 implentation in the form of event trackers. Tracker is an instance
242 of L<FVWM::Tracker> superclass. Currently these tracker classes are
243 available (see their man pages):
245 FVWM::Tracker::Colorsets
246 FVWM::Tracker::GlobalConfig
247 FVWM::Tracker::ModuleConfig
248 FVWM::Tracker::PageInfo
249 FVWM::Tracker::Scheduler
250 FVWM::Tracker::WindowList
252 Using a tracker is easy, something along lines:
254 my $tracker = $module->track("WindowList");
255 my $colorset_tracker = $module->track("Colorsets");
257 Our module that we wrote above may be reduced if we use:
259 my $viewport = $module->track("PageInfo");
261 my $page_nx = $viewport->data("page_nx");
262 my $page_ny = $viewport->data("page_ny");
264 Note that the tracker continues to work and maintain the up-to-date
265 information about the current page and desk (or up-to-date windows
266 or colorsets depending on the tracker type) at any given moment.
268 Internally, trackers listen to appropriate events using the same
269 event handler mechanism, so there is no speed advantage. However
270 it is a good idea to reuse the existing verified code and reduce
271 the number of events needed to be trapped manually. There is
272 usually no problem if the developer and the tracker define
273 handlers for the same events (besides the handler order maybe).
275 :head2 On the module masks
277 In our example above we explicitly defined Mask in constructor.
278 This is not really needed. If not specified, the event mask is
279 managed automatically (it is updated every time a new event handler
282 Note, there are actually two event masks, called "mask" and
283 "xmask" (extended mask). If you are interested in the details,
284 refer to the fvwm documentation or perllib sources.
286 When trackers are added or removed, the module mask (and xmask)
287 are automatically tweaked underhand. In short, there is often no
288 reason to worry about the module masks. However, in rare cases
289 you may want to define SyncMask (or SyncXMask), so that fvwm is
290 synchronized with the module on certain events.
292 :head2 Creating a more functional module
294 Let's extend our new-page-flash example above and add a way to stop
295 our module and to define another string format. This would be
296 possible using the following I<fvwm> commands:
298 SendToModule /path/to/module-flash stop
299 SendToModule /path/to/module-flash format '[%d %d]'
301 To handle such commands, we should define I<M_STRING> event handler.
304 my $format = "(%d, %d)"; # the default format
306 $module->mask($module->mask | M_STRING);
307 $module->add_handler(M_STRING, sub {
308 my ($module, $event) = @_;
309 my $line = $event->_text;
310 my ($action, @args) = get_tokens($line);
312 if ($action eq "stop") {
314 } elsif ($action eq "format") {
319 Now, let's convert our module to be GTK+ based and not to be
320 dependent on I<xmessage>.
322 use lib `fvwm-perllib dir`;
323 use FVWM::Module::Gtk;
324 use POSIX qw(SIGALRM);
327 my $format = "(%d, %d)";
328 my $module = new FVWM::Module::Gtk;
329 my $pageinfo = $module->track("PageInfo");
331 $pageinfo->observe("desk/page changed", sub {
332 my ($module, $tracker, $data) = @_;
334 my $page_nx = $data->{page_nx};
335 my $page_ny = $data->{page_ny};
336 my $width = $data->{vp_width};
337 my $height = $data->{vp_height};
339 # actually show the flash
340 my ($w, $h) = (80, 50);
341 my $string = sprintf($format, $page_nx, $page_ny);
343 my $window = new Gtk::Window('toplevel');
344 $window->set_title("FlashWindow");
345 $window->set_border_width(5);
346 $window->set_usize($w, $h);
347 $window->set_uposition(($width - $w) / 2, ($height - $h) / 2);
349 my $frame = new Gtk::Frame();
350 $window->add($frame);
351 $frame->set_shadow_type('etched_out');
353 my $label = new Gtk::Label($string);
357 POSIX::sigaction(SIGALRM, POSIX::SigAction->new(
358 sub { $window->destroy(); }
365 The full module source that we just wrote is available at
366 ftp://ftp.fvwm.org/pub/fvwm/devel/sources/tests/perl/module-gtkflash .
370 Currently see I<ftp://ftp.fvwm.org/pub/fvwm/devel/sources/tests/perl/>
373 Learning the sources of B<FvwmPerl>, B<FvwmDebug>, B<FvwmGtkDebug>
374 modules may help too.
378 See L<FVWM::Module> and L<FVWM::Module::Gtk> for the module API.
382 Mikhael Goikhman <migo@homemail.com>.
385 $internal_pods->{events} = q{
388 events - list of all fvwm events with arguments
392 This list is automatically generated from L<FVWM::EventNames> package.
394 Given L<FVWM::Event> object of certain event type, say I<M_STRING>,
395 here is the syntax to get value of its I<win_id> argument:
397 $win_id = $event->_win_id;
399 There are several more ways to access arguments, like:
401 $win_id = $event->arg_values->[0];
402 $text = $event->args->{text};
404 :head1 EVENTS WITH ARGUMENTS
408 :head1 ARGUMENT TYPE LEGEND
410 Here is a mapping of fvwm argument types to perl native types:
413 bool - boolean, true or false
414 window - X window id in decimal, use sprintf("0x%07x", $wid)
415 pixel - "rgb:" . join('/', sprintf("%06lx", $val) =~ /(..)(..)(..)/)
416 string - string (scalar)
417 wflags - window flags in binary string
418 looped - loop of zero or more fixed argument bunches
420 Run L<FvwmDebug> or L<FvwmGtkDebug> to browse events.
424 See "tutorial", L<FVWM::Event>, L<FVWM::EventNames> and L<FvwmDebug>.
428 Mikhael Goikhman <migo@homemail.com>.
431 my $topic = $ARGV[0] || "index";
434 if (exists $internal_pods->{$topic}) {
435 $text = $internal_pods->{$topic};
439 if ($topic eq 'index') {
440 my @class_names = sort @{list_filenames($perllibdir, 1)};
441 @class_names = map { s!\.pm$!!; s!/!::!g; $_ } @class_names;
442 $text =~ s/{{CLASS_NAMES}}/join("\n ", @class_names)/seg;
445 if ($topic eq 'events') {
446 my $content = `cat '$perllibdir/FVWM/EventNames.pm'`;
448 foreach ($content =~ /\t&([^\s]+.*?\t\tfields[^\n]+(?:\n\t\t\t[^\n]+)*)/sg) {
449 my ($name, $rest) = /^([^\s]+).*?((?:\n\t\t\t[^\n]+)*)$/s; # ]
450 $result .= " $name\n";
451 $rest =~ s/([^\s]+)\s*=>\s*([\w]+)/
452 $result .= sprintf(" %-16s\t%s\n", $1, $2)
456 $text =~ s!{{EVENT_NAMES}}!$result!se;
460 $file = "$perllibdir/$topic.pm";
462 die "No $file found.\n" unless -f $file;
465 my $man_converter = $do_man ? " | nroff -man | $pager" : "";
466 open(MANPIPE, $do_cat ? "| pod2text '$file' | $pager" :
467 "| pod2man --section 3 --release 'fvwm $version$version_info'" .
468 " --center 'Fvwm Perl library' '$file'" .
469 " | sed 's/<STANDARD INPUT>/perllib/ig'$man_converter")
470 or die "Can't open pipe to pod/man viewer\n";
472 or die "Can't write to pod/man viewer\n";
475 # ---------------------------------------------------------------------------
478 print "Shows documentation of the supplied FVWM Perl library.\n\n";
479 print "Usage: fvwm-perllib man|cat\n";
480 print "\tAn introduction to the FVWM Perl library\n\n";
481 print "Usage: fvwm-perllib man|cat|raw <Perl::Class>\n";
482 print "\tManual page for <Perl::Class>, try: man FVWM::Module\n";
483 print "\t\$PAGER is used for a pager, the default is '$pager'\n\n";
484 print "Usage: fvwm-perllib dir\n";
485 print "\tFor use in fvwm modules written in Perl\n\n";
486 print "Usage: fvwm-perllib [OPTIONS]\n";
488 print "\t--help show this help and exit\n";
489 print "\t--version show the version and exit\n";
499 print STDERR "Try '$0 --help' for more information.\n";
505 # ---------------------------------------------------------------------------
509 fvwm-perllib - shows the documentation of the Fvwm Perl library
514 [ B<--help>|B<-h>|B<-?> ]
515 [ B<--version>|B<-v>|B<-V> ]
516 [ B<man> [ I<Perl::Class> ] ]
517 [ B<cat> [ I<Perl::Class> ] ]
518 [ B<raw> [ I<Perl::Class> ] ]
523 Starting from fvwm-2.5.x versions there is a built-in support for creating
524 fvwm modules in Perl. This B<fvwm-perllib> utility provides help services
525 for the Fvwm Perl library.
530 show the help and exit
533 show the version and exit
535 B<--man> or B<man> [ I<Perl::Class> ]
536 show manual page just like man(1)
538 B<--cat> or B<cat> [ I<Perl::Class> ]
539 show manual page in plain text
541 B<--raw> or B<raw> [ I<Perl::Class> ]
542 generate output in man format (not human readable)
545 print perllib directory without a trailing end of line
549 Use this in the fvwm modules written in Perl:
551 use lib `fvwm-perllib dir`;
553 Introduction to the Fvwm Perl library:
557 Manual page for the C<FVWM::Module> class:
559 % fvwm-perllib man FVWM::Module
563 % fvwm-perllib --help
564 % fvwm-perllib --version
568 Mikhael Goikhman <migo@homemail.com>.
572 The script is distributed by the same terms as fvwm itself.
573 See GNU General Public License for details.
579 Report bugs to fvwm-bug@fvwm.org.
583 # ***************************************************************************