This file is indexed.

/usr/share/perl5/X11/WindowHierarchy.pm is in libx11-windowhierarchy-perl 0.004-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
package X11::WindowHierarchy;
# ABSTRACT: Retrieve information from X11 windows
use strict;
use warnings;
use parent qw(Exporter);

our $VERSION = '0.004';

=head1 NAME

X11::WindowHierarchy - wrapper around L<X11::Protocol> for retrieving the current window hierarchy

=head1 VERSION

version 0.004

=head1 SYNOPSIS

 use X11::WindowHierarchy;

 # Returns a list of all windows with at least one 'word' character in the
 # window title, using the current $ENV{DISPLAY} to select the display and
 # screen
 my @windows = x11_filter_hierarchy(
    filter => qr/\w/
 );
 printf "Found window [%s] (id %d)%s\n", $_->{title}, $_->{id}, $_->{pid} ? ' pid ' . $_->{pid} : '' for @windows;

 # Dump all information we have about all windows on display :1
 use Data::TreeDumper;
 print DumpTree(x11_hierarchy(display => ':1'));

=head1 DESCRIPTION

Provides a couple of helper functions based on L<X11::Protocol> for
extracting the current window hierarchy.

=cut

use X11::Protocol;

our @EXPORT_OK = qw(x11_hierarchy x11_filter_hierarchy);
our @EXPORT    = qw(x11_hierarchy x11_filter_hierarchy);

=head1 FUNCTIONS

The following functions are exported by default, to avoid this:

 use X11::WindowHierarchy qw();

=cut

=head2 x11_hierarchy

Returns a hashref representing the current window hierarchy.

Takes the following named parameters, all of which are optional:

=over 4

=item * display - DISPLAY string, such as ':0'

=item * screen - the screen to use, such as 0 or 1

=back

Returns a hashref structure which contains the following keys:

=over 4

=item * id - the ID for this window

=item * parent - the ID for the parent window

=item * pid - the process ID for this window, if it has one

=item * title - the window name, with any vertical whitespace (such as \n) converted to a single space

=item * icon_name - the icon name

=item * children - an arrayref of any child windows under this

=back

=cut

sub x11_hierarchy {
	my %args = @_;

	# Only pass display if we have it
	my $x = X11::Protocol->new(exists $args{display} ? (delete $args{display}) : ());
	my $screen = delete $args{screen} || 0;

	# Tree walker
	my $code; $code = sub {
		# We get a window ID.
		my $win = shift;

		# Extract all the properties we can
		my %props = map {
			# not entirely sure of the correct parameters for the API here, but, uh... "seems to work"
			$_->[0] => ($x->GetProperty($win, $_->[1], 'AnyPropertyType', 0, 255))[0]
		} map [
			# pretty sure this only returns a scalar, and if it doesn't then we'll break in other ways,
			# but the tests will save us!
			$_ => scalar $x->atom($_, 1)
		], qw(
			_NET_WM_ICON_NAME
			_NET_WM_NAME
			_NET_WM_PID
		);

		# Get all the geometry info apart from the root, since we know that already
		my %geom = $x->GetGeometry($win);
		delete $geom{root};
		@props{keys %geom} = values %geom;

		# Apply our ID
		$props{id} = $win;

		# Grab the pid if we have it
		if(my $pid = delete $props{_NET_WM_PID}) {
			$props{pid} = unpack 'L1', $pid;
		}

		# Get rid of any \n or similar chars, which seem to be legal in window titles for example
		s/[\r\f\n\t\x0B]+/ /g for grep defined, values %props;

		# Remap to something more friendly
		$props{title} = delete $props{_NET_WM_NAME};
		$props{icon_name} = delete $props{_NET_WM_ICON_NAME};

		# Pull a list of all the child windows
		my (undef, $parent, @kids) = $x->QueryTree($win);

		# TODO seems to be consistent, but should check on l10n
		undef $parent if $parent eq 'None';
		$props{parent} = $parent if $parent;

		# ... and recurse for each child window.
		$props{children} = [ ];
		push @{$props{children}}, $code->($_, $win) for @kids;
		return \%props;
	};

	# Start at the root, work down.
	my $tree = $code->($x->{screens}[$screen]{root});

	# and we're done.
	return $tree;
}

=head2 x11_filter_hierarchy

Similar to L</x11_hierarchy> function, but instead of returning a tree hierarchy,
returns a list of windows which match the given criteria.

Takes the same parameters as L</x11_hierarchy>, with the addition of a C< filter >
parameter.

If given a coderef as the filter, this will be called for each window found,
including the window in the output list if the coderef returns a true value.
The hashref representing the window will be passed as the first parameter and
for convenience is also available in $_. The full hierarchy will be constructed
before filtering the list of windows, so you can perform matches based on
the child elements if required.

If given a regex as the filter, returns only the windows whose title matches
the given regex.

=cut

sub x11_filter_hierarchy {
	my %args = @_;
	my $code = delete $args{filter};

	if(ref($code) eq 'Regexp') {
		my $re = $code;
		$code = sub { return unless defined $_->{title}; $_->{title} =~ /$re/ };
	}

	my @out;
	my @pending = x11_hierarchy(%args);
	while(@pending) {
		my $item = shift @pending;
		push @pending, @{$item->{children}};

		# Pass in $_[0] and $_ for convenience.
		push @out, $item for grep $code->($item), $item;
	}
	@out
}

1;

__END__

=head1 EXAMPLES

Get all window IDs for a given PID:

 my @win = map $_->{id}, x11_filter_hierarchy(
    filter => sub { $_->{pid} && $_->{pid} == $pid },
 );

Find the window ID for the largest (as measured by width x height) window
for a given PID:

 use List::UtilsBy qw(max_by);
 my ($win) = max_by {
    $_->{width} * $_->{height}
 } map {
    $_->{id}
 } x11_filter_hierarchy(
    filter => sub {
       $_->{pid} && $_->{pid} == $pid
    },
 );

=head1 SEE ALSO

=over 4

=item * L<X11::Protocol> - provides all the real functionality this module uses

=back

=head1 AUTHOR

Tom Molesworth <cpan@entitymodel.com>

=head1 LICENSE

Copyright Tom Molesworth 2012. Licensed under the same terms as Perl itself.