use X11::Protocol; my $opt_g = 0; my $opt_v = 0; my $do_root = 1; # This is a fudge factor relating to how the X server allocates resource IDs. # 21 seems to be the right value for XFree86 4.2. my $client_shift = 21; $x = new X11::Protocol; sub get_prop { my($win, $name) = @_; return ($x->GetProperty($win, $x->atom($name), $x->atom("STRING"), 0, 65535, 0))[0]; } sub pre_walk { my $win = shift; my($root, $dad, @kids) = $x->QueryTree($win); my @argv = split(/\0/, get_prop($win, "WM_COMMAND")); my $cmd = $argv[0]; $cmd =~ s[^.*/][]; $cmd_name{$win >> $client_shift} = $cmd if $cmd ne ""; map(pre_walk($_), @kids); } sub tree { my $win = shift; my($root, $dad, @kids) = $x->QueryTree($win); my $client = $win >> $client_shift; my $dad_client = $dad >> $client_shift; $id = $win & 0xfffff; my $name = ""; if ($client != $dad_client) { my $client_id = sprintf "%x", $client; $client_id = "$cmd_name{$client}:$client_id" if exists $cmd_name{$client}; $name = "($client_id)"; } $name .= sprintf("%x", $id); if ($opt_g) { my %geo = $x->GetGeometry($win); $name .= "($geo{width}x$geo{height}+$geo{x}+$geo{y})"; } my $title = get_prop($win, "WM_ICON_NAME") || get_prop($win, "WM_NAME"); $name .= "`" . $title ."'" if $title; if (not @kids) { return "-$name\n"; } my @lines; for my $kid (@kids) { push @lines, tree($kid); } my $i; for ($i = $#lines; substr($lines[$i], 0, 1) ne "-"; $i--) { $lines[$i] = " " . $lines[$i]; } if ($i > 0) { $lines[$i] = "`" . $lines[$i]; $lines[$i] = "|" . $lines[$i] while $i-- > 1; $lines[$i] = "+" . $lines[$i]; } else { $lines[0] = "-" . $lines[0]; } return("-$name-" . shift @lines, map(" " x (length($name) + 2) . $_, @lines)); } sub vt_ify { my @x = @_; for my $l (@x) { if ($opt_v) { $l =~ s/\|-/\cNtq\cO/g; $l =~ s/\| /\cNx\cO /g; $l =~ s/`-/\cNmq\cO/g; #`; $l =~ s/---/\cNqqq\cO/g; $l =~ s/-\+-/\cNqwq\cO/g; } } return @x; } pre_walk($x->root); foreach my $arg (@ARGV) { if ($arg eq "-g") { $opt_g = 1; } elsif ($arg eq "-v") { $opt_v = 1; } else { $do_root = 0; print tree(hex $arg); } } print tree($x->root) if $do_root;