#!perl -w
use strict;

# Based on the spy--.pl within the distribution
# Parse a subtree of the whole windoing systme and print as much information as possible
# about each window and each object.
# This software is in a very early stage. Its options and output format will change a lot.
# Your input is welcome !

# Written by Gabor Szabo <gabor@pti.co.il>

# $Id: spy.pl,v 1.3 2004/07/21 21:38:22 szabgab Exp $
my $VERSION = "0.02";

use Getopt::Long;
use Win32::GuiTest qw(:ALL);
my %opts;
GetOptions(\%opts, "help", "title=s", "all", "id=i", "class=s"); 
usage() if $opts{help} or not %opts;


my %seen;
my $desktop = GetDesktopWindow();
my $root    = 0;
my $start;

$start = 0 if $opts{all};
$start = $opts{id} if $opts{id};
if ($opts{title} or $opts{class}) {
	my @windows = FindWindowLike(0, $opts{title}, $opts{class});
	#my @windows = FindWindowLike(0, $opts{title}) if $opts{title};
	#@windows = FindWindowLike(0, '', $opts{class}) if $opts{class};
	if (@windows > 1) {
		print "There are more than one window that fit:\n";
		foreach my $w (@windows) {
			printf "%s | %s | %s\n", $w,  GetClassName($w), GetWindowText($w);
		}
		exit;
	}
	die "Did not find such a window." if not @windows;
	$start = $windows[0];
}






usage() if not defined $start;


my $format = "%-10s %-10s, '%-25s', %-10s, Rect:%-3s,%-3s,%-3s,%-3s   '%s'\n";
printf $format,
		"Depth",
		"WindowID",
		"ClassName",
		"ParentID",
		"WindowRect","","","",
		"WindowText";


parse_tree($start);



sub GetImmediateChildWindows {
	my $WinID = shift;
	grep {GetParent($_) eq $WinID} GetChildWindows $WinID;
}

sub parse_tree {
	my $w = shift;
	if ($seen{$w}++) {
		print "loop $w\n";
		return;
	}

	prt($w);
	#foreach my $child (GetChildWindows($w)) {
	#	parse_tree($child);
	#}
	foreach my $child (GetImmediateChildWindows($w)) {
		print "------------------\n" if $w == 0;
		parse_tree($child);
	}
}

# GetChildDepth is broken so here is another version, this might work better.
 
# returns the real distance between two windows
# returns 0 if the same windows were provides
# returns -1 if one of the values is not a valid window
# returns -2 if the given "ancestor" is not really an ancestor of the given "descendant"
sub MyGetChildDepth {
	my ($ancestor, $descendant) = @_;
	return -1 if $ancestor and (not IsWindow($ancestor) or not IsWindow($descendant));
	return 0 if $ancestor == $descendant;
	my $depth = 0;
	while ($descendant = GetParent($descendant)) {
		$depth++;
		last if $ancestor == $descendant;
	}
	return $depth + 1 if $ancestor == 0;
}


sub prt {
	my $w = shift;
	my $depth = MyGetChildDepth($root, $w);
	printf $format,
		(0 <= $depth ? "+" x $depth : $depth),
		$w, 
		($w ? GetClassName($w) : ""),
		($w ? GetParent($w) : "n/a"),
		($w ? GetWindowRect($w) : ("n/a", "", "", "")),
		($w ? GetWindowText($w) : ""); 
}



sub usage {
	print "Version: v$VERSION\n";
	print "Usage:\n";
	print "        $0 --help\n";
	print "        $0 --all\n";
	print "        $0 --title TITLE\n";
	print "\n";
	print "As the output is quite verbose, probably you'll want to redirect \n";
	print "the output to a file:   $0 options > out.txt\n";
	print "\n";
	exit;
}
