#!/usr/bin/perl -w

# Copyright (C) 2002-2009 Mikhael Goikhman <migo@cpan.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

# Filter this script to pod2man to get a man page:
#   pod2man -c "Fvwm Module" FvwmDebug | nroff -man | less -e

require 5.003;
use strict;

BEGIN {
	use vars qw($prefix $datarootdir $datadir);
	$prefix = "/usr/local";
	$datarootdir = "${prefix}/share";
	$datadir = "${datarootdir}";
}

use lib "${datadir}/fvwm/perllib";
use FVWM::Module;

my $default_mask = MAX_MSG_MASK &
	~(M_FOCUS_CHANGE | M_CONFIGURE_WINDOW | M_VISIBLE_NAME | M_ICON_NAME);
my $default_xmask = MAX_XMSG_MASK &
	~(MX_ENTER_WINDOW | MX_LEAVE_WINDOW | MX_VISIBLE_ICON_NAME);
$default_xmask &= ~M_EXTENDED_MSG;

my $mask  = $default_mask;
my $xmask = $default_xmask;
my $debug = 0;
my $show_args = 1;
my $show_events = undef;
my $log_file = undef;
my $xconsole = 0;
my $log_stream = \*STDERR;
my $send_configinfo = 0;
my $send_windowlist = 0;
my @tracker_names = ();
my @module_args = @ARGV;

my $options = {
	'args!'       => \$show_args,
	'events!'     => \$show_events,
	'l|log=s'     => \$log_file,
	'xc|xconsole' => \$xconsole,
	'm|mask=i'    => \$mask,
	'x|xmask=i'   => \$xmask,
	'sc|send-configinfo' => \$send_configinfo,
	'sw|send-windowlist' => \$send_windowlist,
	'd|debug=i'   => \$debug,
	't|track=s'   => \@tracker_names,
};

my $module = new FVWM::Module(
	Name  => "FvwmDebug",
	Debug => \$debug,
	EnableOptions => $options,
);

$show_events = (@tracker_names ? 0 : 1) unless defined $show_events;
$mask  = MAX_MSG_MASK  if $mask  == -1;
$xmask = MAX_XMSG_MASK if $xmask == -1;

$module->debug("argv = '" . join("', '", @module_args) . "'\n");
$module->mask($mask);
$module->xmask($xmask);

#$module->add_handler($mask, \&show_event);
#$module->add_handler($xmask | M_EXTENDED_MSG, \&show_event);
$module->add_handler(MAX_MSG_MASK, \&show_event);
$module->add_handler(MAX_XMSG_MASK | M_EXTENDED_MSG, \&show_event);

$module->add_handler(ON_EXIT, sub { system("killall xconsole"); }) if $xconsole;
$log_file = '|xconsole -file /dev/stdin -geometry 600x400 -notify' if $xconsole;

if ($log_file) {
	# let's hope the system will close it automatically on exit
	my $prefix = $log_file =~ /^\s*\|/ ? "" : ">";
	open $log_stream, "$prefix$log_file";
}

foreach my $name (@tracker_names) {
	my $tracker = $module->track($name);
	$module->debug(
		"$name: initialized\n" . $tracker->dump . ("-" x 74), 0
	);
	$tracker->observe("main", sub {
		my ($module, $tracker, $info, @params) = @_;
		my $headline = "$name: " . $tracker->observables->[0];
		$module->debug(
			"$headline\n" . $tracker->dump(@params) . ("-" x 74), 0
		);
	});
}

$module->send("Send_ConfigInfo") if $send_configinfo;
$module->send("Send_WindowList") if $send_windowlist;

$module->event_loop;

sub show_event ($$) {
	return unless $show_events;
	my ($module, $event) = @_;

	unless ($show_args) {
		print $log_stream $event->name, "\n";
		return;
	}
	print $log_stream $event->dump;
}

__END__

# ----------------------------------------------------------------------------
# man page

=head1 NAME

FvwmDebug - the fvwm module debugger

=head1 SYNOPSIS

FvwmDebug should be spawned by fvwm(1) for normal functionality.

To run this module, place this command somewhere in the configuration:

    Module FvwmDebug [optional-params]

To stop this module, execute:

    KillModule FvwmDebug

=head1 DESCRIPTION

This module persistently dumps all fvwm event details and optionally some
other information into the standard error stream or a file, good for
debugging purposes. The output may be optionally redirected to I<xconsole>
or similar window.

=head1 INVOCATION

There are several command line switches:

B<FvwmDebug>
[ B<--args>|B<--noargs> ]
[ B<--events>|B<--noevents> ]
[ B<--log> I<file> ]
[ B<--xconsole> ]
[ B<--mask> I<mask> ]
[ B<--xmask> I<mask> ]
[ B<--debug> I<level> ]
[ B<--track> I<tracker-name> ]
[ B<--send-configinfo> ]
[ B<--send-windowlist> ]

Long switches may be abbreviated to shorter switches.

B<--noargs> - do not print all arguments of the event, just its name.
B<--args> is the default.

B<--noevents> - do not print even event names, implies B<--noargs>.
It is similar in effect to setting both B<--mask> and B<--xmask> to 0,
but the events are actually received by the module, they are just not printed.

This option may be useful if B<--track> or/and B<--debug> is used.

The default is B<--events> normally, and B<--noevents> if one or more
B<--track> options specified.

B<-l>|B<--log> I<file> - specify the log file name instead of the standard
error stream. If the log file can't be open for writting, the default
standard error stream is used.

The I<file> may start with a pipe '|', this is similar to the usual meaning
of a pipe, the output is piped to the specified command. See also
B<--xconsole> option.

B<-xc>|B<--xconsole> - this is a shortcut for:

    FvwmDebug --log '|xconsole -file /dev/stdin -geometry 600x400 -notify'

That shows the module output in the I<xconsole> window rather than
the standard error stream.

B<-m>|B<--mask> I<mask> - set the module mask, 31 bit integer.
By default almost all events are monitored (except for some flood events
like I<CONFIGURE_WINDOW> or I<FOCUS_WINDOW>. The special value of I<-1>
sets the maximal mask.

B<-x>|B<--xmask> I<mask> - set the module extended mask, 31 bit integer.
By default almost all events are monitored (except for some flood events
like I<ENTER_WINDOW> or I<LEAVE_WINDOW>. The special value of I<-1>
sets the maximal extended mask.

B<-d>|B<--debug> I<level> - use the Perl library debugging mechanism.
The useful I<level>s are 2 to 4.

B<-t>|B<--track> I<tracker-name> - create the given Perl library tracker and
observe its main observable. This option may be specified multiple times.
This options implies B<--noevents> unless explicitely overwritten.
You may optionally try B<--debug>, for example:

    FvwmDebug -xc --track PageInfo --track GlobalConfig --debug 3

Run "fvwm-perllib man" to get the names of all existing trackers in your
installed Perl library.

B<-sc>|B<--send-configinfo> - send B<Send_ConfigInfo> command to I<fvwm>
on startup, this results in a lot of events received.

B<-sw>|B<--send-windowlist> - send B<Send_WindowList> command to I<fvwm>
on startup, this results in a lot of events received.

=head1 SEE ALSO

See also L<FvwmGtkDebug>.

=head1 AUTHOR

Mikhael Goikhman <migo@homemail.com>.

=cut
