This file is indexed.

/usr/share/perl5/X11/Protocol/ChooseWindow.pm is in libx11-protocol-other-perl 30-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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
# Copyright 2011, 2012, 2013, 2014, 2016, 2017 Kevin Ryde

# This file is part of X11-Protocol-Other.
#
# X11-Protocol-Other 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 3, or (at your option) any
# later version.
#
# X11-Protocol-Other 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 X11-Protocol-Other.  If not, see <http://www.gnu.org/licenses/>.


BEGIN { require 5 }
package X11::Protocol::ChooseWindow;
use strict;
use Carp;

use vars '$VERSION', '$_instance';
$VERSION = 30;

use X11::Protocol::WM;

# uncomment this to run the ### lines
# use Smart::Comments;


# undocumented yet ...
sub new {
  my $class = shift;
  return bless { want_client => 1,
                 @_ }, $class;
}

sub _X {
  my ($self) = @_;
  return ($self->{'X'} ||= do {
    require X11::Protocol;
    my $display = $self->{'display'};
    ### $display
    X11::Protocol->new (defined $display ? ($display) : ());
  });
}

sub choose {
  my ($self, %options) = @_;
  unless (ref $self) {
    $self = $self->new;  # X11::Protocol::ChooseWindow->choose()
  }
  local @{$self}{keys %options} = values %options;  # hash slice
  local $_instance = $self;

  my $X = _X($self);
  {
    my $old_event_handler = $X->{'event_handler'};
    local $X->{'event_handler'} = sub {
      $self->handle_event (@_);
      goto $old_event_handler;
    };

    $self->start;
    do {
      $X->handle_input;
    } until ($self->is_done);
  }

  return $self->chosen_window;
}

sub chosen_window {
  my ($self) = @_;
  if ($self->{'want_client'}) {
    return $self->client_window;
  } else {
    return $self->{'frame_window'};
  }
}
sub client_window {
  my ($self) = @_;
  if (! exists $self->{'client_window'}) {
    my $frame_window = $self->{'frame_window'};
    ### frame_window: $frame_window.sprintf('  0x%X',$frame_window)
    $self->{'client_window'}
      = (defined $frame_window && _num_none($frame_window) != 0
         ? X11::Protocol::WM::frame_window_to_client(_X($self),$frame_window)
         : undef);
    ### client_window: $self->{'client_window'}
  }
  return $self->{'client_window'};
}

# undocumented yet ...
sub start {
  my ($self) = @_;

  $self->abort;
  $self->{'frame_window'} = undef;
  delete $self->{'client_window'};
  $self->{'button_released'} = 0;
  my $X = _X($self);

  my $want_free_cursor;
  my $cursor = $self->{'cursor'};
  if (! defined $cursor) {
    my $cursor_glyph = $self->{'cursor_glyph'};
    if (! defined $cursor_glyph) {
      require X11::CursorFont;
      my $cursor_name = $self->{'cursor_name'};
      if (! defined $cursor_name) {
        $cursor_name = 'crosshair';  # default
      }
      $cursor_glyph = $X11::CursorFont::CURSOR_GLYPH{$cursor_name};
      if (! defined $cursor_glyph) {
        croak "Unrecognised cursor_name: ",$cursor_name;
      }
    }

    my $cursor_font = $X->new_rsrc;
    $X->OpenFont ($cursor_font, 'cursor');

    $cursor = $X->new_rsrc;
    $X->CreateGlyphCursor ($cursor,
                           $cursor_font,  # font
                           $cursor_font,  # mask font
                           $cursor_glyph,    # glyph number
                           $cursor_glyph+1,  # and its mask
                           0,0,0,                    # foreground, black
                           0xFFFF, 0xFFFF, 0xFFFF);  # background, white
    $want_free_cursor = 1;
    $X->CloseFont ($cursor_font);
  }
  ### cursor: sprintf '%d %#X', $cursor, $cursor

  my $root = $self->{'root'};
  if (! defined $root) {
    if (defined (my $screen_number = $self->{'screen'})) {
      $root = $X->{'screens'}->[$screen_number]->{'root'};
    } else {
      $root = $X->{'root'};
    }
  }
  ### $root

  # follow any __SWM_VROOT
  $root = (X11::Protocol::WM::root_to_virtual_root($X,$root) || $root);

  my $time = $self->{'time'} || $self->{'event'}->{'time'} || 'CurrentTime';
  ### $time

  my $status = $X->GrabPointer
    ($root,          # window
     0,              # owner events
     $X->pack_event_mask('ButtonPress','ButtonRelease'),
     'Synchronous',  # pointer mode
     'Asynchronous', # keyboard mode
     $root,          # confine window
     $cursor,        # crosshair cursor
     $time);
  if ($status eq 'Success') {
    $self->{'ungrab_time'} = $time;
  }
  if ($want_free_cursor) {
    $X->FreeCursor ($cursor);
  }
  if ($status ne 'Success') {
    croak "Cannot grab mouse pointer to choose a window: ",$status;
  }
  $X->AllowEvents ('SyncPointer', 'CurrentTime');
}

# undocumented yet ...
sub handle_event {
  my ($self, %h) = @_;
  ### ChooseWindow handle_event: %h
  return if $self->is_done;

  my $name = $h{'name'};
  my $X = _X($self);

  if ($name eq 'ButtonPress') {
    ### ButtonPress
    $self->{'frame_window'} = $h{'child'};
    $self->{'choose_time'} = $h{'time'};
    $X->AllowEvents ('SyncPointer', 'CurrentTime');

  } elsif ($name eq 'ButtonRelease') {
    ### ButtonRelease
    # wait for button pressed to choose window, and then released so the
    # release event doesn't go to the chosen window
    if ($self->{'frame_window'}) {
      # button press seen, and now release seen
      $self->{'button_released'} = 1;
      $self->{'ungrab_time'} = $h{'time'};
      $self->abort;  # ungrab
    } else {
      $X->AllowEvents ('SyncPointer', 'CurrentTime');
    }
  }
}

# undocumented yet ...
sub is_done {
  my ($self) = @_;
  return (! defined $self->{'ungrab_time'} # aborted or never started
          || ($self->{'frame_window'} && $self->{'button_released'}));
}

sub DESTROY {
  my ($self) = @_;
  my ($X, $ungrab_time);
  if (defined ($X = $self->{'X'})
      && defined ($ungrab_time = delete $self->{'ungrab_time'})) {
    # no errors if connection gone
    eval { $X->UngrabPointer ($ungrab_time) };
  }
}

# undocumented yet ...
sub abort {
  my ($self, $time) = @_;
  if (! ref $self) {
    # class method X11::Protocol::ChooseWindow->abort()
    $self = $_instance || return;  # if not in a ->choose()
  }
  my ($X, $ungrab_time);
  if (defined ($X = $self->{'X'})
      && defined ($ungrab_time = delete $self->{'ungrab_time'})) {
    $X->UngrabPointer ($time || $ungrab_time);
  }
}

sub _num_none {
  my ($xid) = @_;
  if (defined $xid && $xid eq "None") {
    return 0;
  } else {
    return $xid;
  }
}

1;
__END__


# Not quite yet.

# =head2 Chooser Object
# 
# A chooser object can be created to choose in a state-driven style.
# 
# =over
# 
# =item C<$chooser = X11::Protocol::ChooseWindow-E<gt>new (key=E<gt>value,...)>
# 
# Create and return a chooser object.  The key/value parameters are the same
# as for C<choose()> above.
# 
# =item C<$window = $chooser-E<gt>choose (key=E<gt>value,...)>
# 
# Run a window choose on C<$chooser>.  Key/value parameters are as per the
# C<choose()> class method above.  They're apply to this choose, without
# changing the C<$chooser> object.
# 
# =item C<$boolean = $chooser-E<gt>start ()>
# 
# Start a window choose.  This means a mouse pointer grab, with cursor per the
# options in C<$chooser>.
# 
# =item C<$window = $chooser-E<gt>handle_event (@fields)>
# 
# Handle an event in C<$chooser>.  The C<@fields> arguments are the same as
# from the C<X11::Protocol> event handler function.  All events should be
# shown to the chooser this way while it's active.  Anything not relevant is
# ignored.
#
# For a C<ButtonPress> or C<ButtonRelease> event an C<AllowEvents> request
# is sent to get the next button event, in the usual way for an active
# pointer grab.
# 
# =item C<$boolean = $chooser-E<gt>is_done ()>
# 
# Return true if choosing is finished, meaning C<$chooser-E<gt>handle_event()>
# has seen button press and release events.
# 
# =item C<$chooser-E<gt>abort>
# 
# Stop a choose.
# 
# =item C<$chooser-E<gt>chosen_window>
# 
# Return the window chosen by the user, or C<undef> if aborted or not yet
# chosen.  This can be used after C<$chooser-E<gt>is_done()> is true (though
# actually the chosen window is recorded a little earlier, on the button
# press, where C<is_done()> is true only after the button release).
# 
# =back

#     want_frame_window   boolean, default false
# 
# C<want_frame_window> means return the immediate root window child chosen,
# which is generally the window manager's frame window.  The default is to
# seek the client toplevel window within the frame.  When there's no window
# manager or it doesn't use frame windows then the immediate child is the
# client window already and C<want_frame_window> has no effect.





=for stopwords Ryde ChooseWindow toplevel timestamp startup crosshair

=head1 NAME

X11::Protocol::ChooseWindow -- user click to choose window

=for test_synopsis my ($X)

=head1 SYNOPSIS

 use X11::Protocol::ChooseWindow;
 my $client_window = X11::Protocol::ChooseWindow->choose (X => $X);

=head1 DESCRIPTION

This spot of code lets the user click on a toplevel window to choose it, in
a similar style to the C<xwininfo> or C<xkill> programs.

=head2 Implementation

The choose is implemented in a similar way to the C<xwininfo> etc programs.
It consists of C<GrabPointer()> on the root window, wait for a
C<ButtonPress> and C<ButtonRelease> from the user, get the frame window from
the C<ButtonPress> event, then the client window under there from
C<frame_window_to_client()> of C<X11::Protocol::WM>.

C<KeyPress> events are not used and they go to the focus window in the usual
way.  This can be good in a command line program since it lets the user
press C<^C> (C<SIGINT>) in an C<xterm> or similar.  Perhaps in the future
there could be an option to watch for C<Esc> to cancel or some such.

A virtual root per C<root_to_virtual_root()> in C<X11::Protocol::WM> is used
if present.  This helps C<ChooseWindow> work with C<amiwm> and similar
virtual root window managers.

=head1 FUNCTIONS

The following C<choose()> is in class method style with the intention of
perhaps in the future having objects of type C<X11::Protocol::ChooseWindow>
holding state and advanced by events supplied by an external main loop.

=head2 Choosing

=over 4

=item C<$window = X11::Protocol::ChooseWindow-E<gt>choose (key=E<gt>value,...)>

Read a user button press to choose a toplevel window.  The key/value options
are as follows,

    X        => X11::Protocol object
    display  => string ":0:0" etc

    screen   => integer, eg. 0
    root     => XID of root window

    time     => integer server timestamp
    event    => hashref of event initiating the choose

    cursor       => XID of cursor
    cursor_glyph => integer glyph for cursor font
    cursor_name  => string name from cursor font

C<X> or C<display> gives the server, or the default is to open the
C<DISPLAY> environment variable.  C<X> for an C<X11::Protocol> object is
usual, but sometimes it can make sense to open a new connection just to
choose.

C<root> or C<screen> gives the root window to choose on, or the default is
the current screen of C<$X>, which in turn defaults to the screen part of
the display name.  If there's a window manager virtual root then that's
automatically used as necessary.

C<time> or the time field in C<event> is a server timestamp for the
C<GrabPointer()>.  This guards against stealing a grab from another client
if badly lagged.  Omitted or C<undef> means C<CurrentTime>.  In a command
line program there might be no initiating event, making C<CurrentTime> all
that's possible.

C<cursor> etc is the mouse pointer cursor to show during the choose, as a
visual indication to the user.  The default is a "crosshair".
C<cursor_name> or C<cursor_glyph> are from the usual cursor font.  See
L<X11::CursorFont> for available names.  For example perhaps the "exchange"
cursor to choose a window for some sort of swap or flip,

    $window = X11::Protocol::ChooseWindow->choose
                (X => $X,
                 cursor_name => "exchange");

A C<cursor> XID can be created by any client as usual.  Don't forget to
flush if creating a cursor from one connection, so it's ready for use from
another.

=back

=head1 SEE ALSO

L<X11::Protocol>,
L<X11::Protocol::WM>,
L<X11::CursorFont>

L<xwininfo(1)>, L<xkill(1)>, and their F<dsimple.c> C<Select_Window()> code

"Inter-Client Communication Conventions Manual" section "WM_STATE Property"
for notes on using C<WM_STATE> to identify client windows.

=head1 HOME PAGE

L<http://user42.tuxfamily.org/x11-protocol-other/index.html>

=head1 LICENSE

Copyright 2010, 2011, 2012, 2013, 2014, 2016, 2017 Kevin Ryde

X11-Protocol-Other 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 3, or (at your option) any later
version.

X11-Protocol-Other 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
X11-Protocol-Other.  If not, see <http://www.gnu.org/licenses/>.

=cut


# Maybe:
#
# oopery
# ->new (want_frame => 1)
# ->choose
# ->start
# ->handle_input
# ->is_done
# ->chosen_frame
# ->chosen_client
# ->chosen_window

# /usr/share/doc/x11proto-core-dev/x11protocol.txt.gz