#!/usr/bin/perl
#

#:META:X_RESOURCE:noscreen:boolean:Do not run screen in this window
#:META:X_RESOURCE:nolayout:boolean:Do not remember/reuse region layouts
#:META:X_RESOURCE:fancyButtons:boolean:Show a fancy 3 bar menu icon
#:META:X_RESOURCE:screenid:string:Sesson ID name for screen to attach/create
#:META:X_RESOURCE:host:string:Remote host to SSH to before running screen
#:META:X_RESOURCE:latency:number:Latency threshold remote screen sessions
#:META:X_RESOURCE:screenexe:string:Path to screen executable

=head1 NAME

screen - rxvt-unicode (urxvt) module to interface with GNU screen

=head1 SYNOPSIS

urxvt [options] [-noscreen] [-fancyButtons] [-screenid string]
[-host string] [-latency #]

=head2 Options

=over

=item -noscreen

Do not start screen, even if the invocation is for a login shell.

=item -nolayout

Do not remember or reuser region layouts.  This options has two effects.
If used, the screen will not store it's layout by default.  Which means
that a re-attach will start with one region occupying the entire space.
Additionally, if this option is used when re-attaching to an existing
session, ignore the layout and start up with one region occupying the entire
space of the L<urxvt(1)> window.

This option has no effect on versions of L<screen(1)> which do not support
layouts, as they will be automatically disabled anyway.

=item -fancyButtons

Display fancy buttons which L<screen(1)> has a problem with.  This feature
only works on terminals with UTF-8 locales and requires extra CPU.

=item -screenid string

Tell L<screen(1)> to name the session based on C<string>.  By default
L<screen(1)> will create a name based on the PTY it is attached to.  This
option affects how L<screen(1)> is invoked by the B<screen> extenstion;
with this option L<screen(1)> is run with the C<-x> command-line option
to re-attach to the session named by C<string>.

=item -host string

Before running the L<screen(1)> command, use L<ssh(1)> to connect to the
remote host C<string> and run L<screen(1)> there.  Since integration between
the B<screen> extension and the L<screen(1)> program is entirely terminal
based, there is no requirement to run screen locally.

=item -latency milliseconds

Millisecond latency allowance for screen re-draws when trying to find a
new screen after it is selected.  The default is 10 milisecond for local
screen sessions, and 50 milliseconds for remote screen sessions.  Increase
this value if a remote screen session fails to find the correct window when
changing focus.

=back

=head1 DESCRIPTION

The B<screen> extension manages the interaction between a terminal and the
GNU screen system.  A caption bar will be set to drive the interface.  If you
already have a caption bar setting, it will be overridden when screen is
initialized.  This bar will act as your tab bar, and is mouse accelerated.

Features are enabled or disabled based on the version of L<screen(1)>.
Additionally, actions are simulated by the URxvt B<screen> extension on
older versions of L<screen(1)>.

=head2 Resources

Enabling the screen extension can be done on the command-line via the
C<-pe screen> L<urxvt(1)> command-line option, or by setting the
XResouce string C<URxvt.perl-ext-common> as such:

   URxvt.perl-ext-common: ...,screen,...

Additionally, the color of the caption bar can be controlled by XResources.
The following XResources are available which affect the B<screen> extension:

=over 8

=item URxvt.screen.captionBar:  color

This is the bar part of the caption, which is in essence a terminal background
color.  Default is inverse video.  This changes the color from inverse video to
C<color>.  The C<color> must exist in the color table defined below.

=item URxvt.screen.captionColor: color

This is the text part of the caption.  Default is inverse video, so it would
default to the normal terminal background color.  This changes the color
from inverse video to C<color>.  The C<color> must exist in the color table
defined below.

The author strongly recommends you try setting C<URxvt*screen.captionBar>
to C<gray> in your F<.Xresource> file.  This color
seems to work well for most background color options and background pixmap
choices.  It is a nice, muted option to compare against other alternatives
which may fit better with your desktop theme.

=item URxvt.screen.captionActive: color

Active tabs have no background, the terminal background shows through (color
or pixmap).  This parameter specifies the text color used to display the active
tab.  The default for this color is the same as the C<URxvt.screen.captionBar>
color.  N.B., this entry is underlined with the same color.  If you change
the color, then you will change the underline color.  If this behaviour is
not desired, see the C<URxvt*underlineColor> resource entry from the
L<urxvt(1)> man page.

=item URxvt.screen.nolayout: boolean

This resource is the same as the C<-nolayout> command-line option.

=item URxvt.screen.fancyButtons: boolean

This resource is the same as the C<-fancyButtons> command-line option.  It
will make fancy buttons on Unicode capable terminals.  This option requires
more CPU.

=back

The allowed colors are as follows (items sharing a line are synomyms):

  black
  gray, gray25, grey
  red
  red2
  green
  lime
  gold, darkyellow
  yellow
  blue
  blue2
  magenta
  violet
  cyan
  azure
  lightgray, offwhite, antiquewhite
  white

=cut

my(%SCREEN_CMAP)=(
	'black'		=> 'k',
	'gray'		=> 'K',
	'grey'		=> 'K',
	'gray25'		=> 'K',
	'red'		=> 'r',
	'red2'		=> 'R',
	'green'		=> 'g',
	'lime'		=> 'G',
	'gold'		=> 'y',
	'darkyellow'	=> 'y',
	'yellow'		=> 'Y',
	'blue'		=> 'b',
	'blue2'		=> 'B',
	'magenta'		=> 'm',
	'violet'		=> 'M',
	'cyan'		=> 'c',
	'azure'		=> 'C',
	'lightgray'	=> 'w',
	'offwhite'	=> 'w',
	'antiquewhite'	=> 'w',
	'white'		=> 'W',
	''			=> 'd',
);

=head2 Interface

Each region will have a caption bar at the bottom.  If you define a
specific caption bar in your system or personal F<screenrc> files, it
will be overridden by the B<screen> extension.  This extension cannot be
used without its caption bar.

The caption bar will begin with a clickable plus (+) symbol.  This will create
a new tab (a.k.a. L<screen(1)> window) if selected with button 1 of the mouse.
The caption bar will end with an equal (=) symbol.  This will open a menu with
common tasks if selected with button 1 of the mouse.

=cut

my($NT, $NTU)=("+\240", "\N{U+2295}\240");
my($MU, $MUU)=("\240=", "\240\N{U+2261}");

my(@SCREEN_METHODS)=qw(
	init child_start configure_notify osc_seq_perl
	button_press button_release motion_notify sel_extend
	line_update
);

sub screen {
	my($self, $command)=@_;

	if($command=~m/^:.*\S$/) {
		$command=~s/^:/:\@/ if($self->{'silentops'});
		$self->tt_paste("\001$command\n");
	} else {
		$self->tt_paste("\001$command");
	}
}

=pod

The menu contains the following functions:

=over 8

=item Lock

Lock the screen sessoin and wait for a password to re-attach.

=item Blank

Blank the screen so it appears empty.  Any keypress will restore the visual.

=item Detach

Detach from the screen session.  Your screen will remain running and available
for re-attach, but the terminal window will close.

=item Grow v or Shrink ^

Increase or Decrease the size of a screen region by one row.  It is usually
easier to grab the caption bar and just drag it.  On older versions of screen
which don't have vertical splitting, the C<v> and C<^> characters are not
drawn, as this is the only kind of resizing available.

=item Grow > or Shrink <

Increase or Decrease the size of a screen region by one column.  It is usually
easier to grab the caption bar and just drag it.

=item Fit

Resize a screen window to fit the region encompassing it.  This is really
useful if you want to move a tab to a specific region which has a different
size.  This works a lot like running C<eval "`resize`">, but is aware of the
geometry of screen regions, so works better.

=item Remove

Close a region.  The tab (aka window) running in that window will not be
closed.  Only the region and it's frame will be removed.  This will cause
the surrounding regions to be resized to consume the space.

=item Join

Join all regions into one.  This will make your session look like it does
after initial startup.

=item Split |

Perform a vertical split.  The region will be split down the middle.  This
is a new feature and not available in all versions of L<screen(1)>.  If
your version is too old, you may not see this menu option.  Vertical
splits make selecting text more difficult, and this should be taken into
account before using this feature too heavily.

=item Split -

Perform a horizontal split.  The current region will be split evenly between
a top and bottom region.

=item Windowlist

Display a menu of all windows from which you can select the window/tab on
which to focus.  This item is especially useful when using the grouping
feature in L<screen(1)> as it displays the group hierarchies.

=item Close Tab

Have L<screen(1)> tell the shell running under a tab (aka window) to close.
You will be asked to confirm this request.

=item New Tab

Create a new tab (aka window) just as would be done with the plus (+) sign
option on the other side of the caption bar.

=item Run

Run an application in a new tab.

=back

=cut

sub menu {
	my($self, $event)=@_;
	my(@m)=();
	my($menu);

	#Menu Definition:
	push(@m,	'Lock'		=> sub { &screen($self, 'x') });
	push(@m,	'Blank'		=> sub { &screen($self, ':blanker') });
	push(@m,	'Detach'		=> sub { &screen($self, 'd') });
	push(@m,	'='			=> '-');
	if($self->{'vsplit'} && @{$self->{'regions'}}>1) {
		push(@m, 'Grow   v'	=> sub { &screen($self, ':resize -v +1') });
		push(@m, 'Shrink ^'	=> sub { &screen($self, ':resize -v -1') });
		push(@m, 'Grow   >'	=> sub { &screen($self, ':resize -h +1') });
		push(@m, 'Shrink <'	=> sub { &screen($self, ':resize -h -1') });
	} elsif($self->{'vsplit'}) {
		push(@m, 'Grow   v'	=> undef);
		push(@m, 'Shrink ^'	=> undef);
		push(@m, 'Grow   >'	=> undef);
		push(@m, 'Shrink <'	=> undef);
	} elsif(@{$self->{'regions'}}>1) {
		push(@m, 'Grow'	=> sub { &screen($self, ':resize +1') });
		push(@m, 'Shrink'	=> sub { &screen($self, ':resize -1') });
	} else {
		push(@m, 'Grow'	=> undef);
		push(@m, 'Shrink'	=> undef);
	}
	push(@m,	'='			=> '-');
	push(@m,	'Fit'		=> sub { &screen($self, ':fit') });
	if(@{$self->{'regions'}}>1) {
		push(@m,	'Remove'	=> sub { &screen($self, 'X') });
		push(@m,	'Join'	=> sub { &screen($self, 'Q') });
	} else {
		push(@m,	'Remove'	=> undef);
		push(@m,	'Join'	=> undef);
	}
	push(@m,	'Split |'		=> sub { &screen($self, '|') }) if($self->{'vsplit'});
	push(@m,	'Split -'		=> sub { &screen($self, 'S') });
	push(@m,	'='			=> '-');
	push(@m,	'Windowlist'	=> sub {	&screen($self, ':windowlist -b -g');
								$self->tt_paste("a"); });
	push(@m,	'Close Tab'	=> sub { &screen($self, 'K') });
	push(@m,	'New Tab'		=> sub { &screen($self, 'c') });
	push(@m,	'Run'		=> sub { &screen($self, ':screen ') });

	#Display Menu:
	$event->{'y_root'}-=(@m/2)*$self->fheight()+3;
	$event->{'x_root'}-=5*$self->fwidth();

	$menu=$self->popup($event);

	for(my $i=0; $i<@m; $i+=2) {
		if($m[$i] eq '=') {
			$menu->add_separator($m[$i+1]);
		} elsif(defined($m[$i+1])) {
			$menu->add_button($m[$i] => $m[$i+1]);
		} else {
			$menu->add_separator("\e[37;1m".$m[$i].'        ');
		}
	}

	$menu->show;
}

=head2 Regions

The L<screen(1)> application supports regions.  Regions split a terminal into
sub-sections.  These regions can split a terminal horizontally or (on newer
versions) vertically.  The B<screen> extension screen scrapes the terminal
to identify the geometry of all the regions in a terminal.  This region map
is used to identify when operations such as tab selection, menu requests,
or resizing of regions is requested.

=cut

sub regions {
	my($self)=@_;
	my($line, $top, $left, $right);
	my($rows, $cols)=($self->nrow()-1, $self->ncol()-1);

	$self->{'regions'}=[];

	unless(defined($self->{'user_rstyle'})) {
		$self->{'user_rstyle'}=${$self->ROW_r($rows)}[0];
	}

	foreach my $row (0 .. $rows) {
		$line=$self->ROW_t($row);
		next unless($line=~m/(\Q$NT\E|\Q$NTU\E).*?(\Q$MU\E|\Q$MUU\E)/);
		
		$left=$right=0;

		while($right<$cols) {
			if($self->{'fancyButtons'}) {
				$left=index($line, $NTU, $right);
				$right=index($line, $MUU, $left)+1;
			} else {
				$left=index($line, $NT, $right);
				$right=index($line, $MU, $left)+1;
			}

			last if($left==-1 || $right==-1);

			$top=0;
			foreach my $r (@{$self->{'regions'}}) {
				if($r->[2]>=$top && $r->[1]<=$left && $left<=$r->[3]) {
					$top=$r->[2]+1;
				}
			}
			push(@{$self->{'regions'}}, [$top, $left, $row, $right]);
		}
	}
}

=pod

This screen scraping is a major reason why the B<screen> extension must define
its own caption bar the screen initialization process.  The caption bar is
the scraped text used to define all region information for the screen.

If you were to disable the caption bar or change it during a running
L<screen(1)> session, many of the features of this extension would cease to
function.  Any personalization of caption colors should be done using the
XResources defined above.

=cut

sub init_screen {
	my($self)=@_;
	my($tb)=$SCREEN_CMAP{$self->x_resource('%.screen.captionActive')};
	my($fg)=$SCREEN_CMAP{$self->x_resource('%.screen.captionColor')};
	my($bg)=$SCREEN_CMAP{$self->x_resource('%.screen.captionBar')};
	my($lmu)=length($MU);
	my($caption)="$NT%-w%{=u $tb$bg} %n %t %{-}%+w%-${lmu}=$MU";

	&screen($self, ':mousetrack off')	if($self->{'mousetrack'});
	&screen($self, ":$self->{'so'} $fg$bg");
	&screen($self, ":caption always '$caption'");

	if($self->{'layouts'}) {
		if($self->{'nolayout'}) {
			&screen($self, ":layout autosave off");
			&screen($self, 'Q');
		} else {
			&screen($self, ":layout save 0");
			&screen($self, ":layout autosave on");
		}
	}
}

=pod

Because the B<screen> extension knows the geometry of all the regions, it can
distinguish between them.  This is a big selling feature of the B<screen>
extension over the the built-in L<screen(1)> C<mousetrack> feature.  You can
select text inside a region as normal when using the B<screen> extension.
Furthermore, focusing is not just specific to regions, but also to tabs
within those regions.

The B<screen> extension can find both bottom borders (caption bar) and
vertical borders between regions.

=cut

sub caption_click {
	my($self, $event)=@_;
	my($row, $col)=($event->{'row'}, $event->{'col'});
	my($t, $l, $b, $r);

	foreach my $region (@{$self->{'regions'}}) {
		($t, $l, $b, $r)=@$region;
		return(1) if($b==$row && $l<=$col && $col<=$r);
	}
	return(0);
}

sub border_click {
	my($self, $event)=@_;
	my($row, $col)=($event->{'row'}, $event->{'col'});
	my($t, $l, $b, $r);

	foreach my $region (@{$self->{'regions'}}) {
		($t, $l, $b, $r)=@$region;
		return(1) if($r+1==$col && $t<=$row && $row<$b);
	}
	return(0);
}

=pod

The downside of defining the regions from screen scrape is that the
B<screen> extension does not know the order of regions.  Because of this
to go to one region from another, it will progress iteratively until the
correct region is in focus.  This process is sometimes visible to the user,
as the latency of transitions is accounted for.  This is especially noticable
for remote L<screen(1)> sessions started using the C<-host> command-line.
If transitions seem to be ending in the wrong region, use the C<-latency>
command-line option to allow more time for transition completion.

=cut

sub get_region {
	my($self, $row, $col)=@_;
	my($t, $l, $b, $r);

	return(-$self->saveLines(), 0, -1, $self->ncol()-1) if($row<0);

	foreach my $i (0 .. $#{$self->{'regions'}}) {
		($t, $l, $b, $r)=@{$self->{'regions'}[$i]};

		if($t<=$row && $row<=$b && $l<=$col && $col<=$r) {
			return($t, $l, $b, $r);
		}
	}

	return(0, 0, 0, 0);
}

sub goto {
	my($self, $event)=@_;
	my($tor, $toc)=($event->{'row'}, $event->{'col'});
	my($t, $l, $b, $r);
	my($max)=$#{$self->{'regions'}};

	($t, $l, $b, $r)=&get_region($self, $tor, $toc);

	$self->{'timer'}=urxvt::timer->new()->cb(sub {
		my($timer)=@_;
		my($row, $col)=$self->screen_cur();

		if(!$max-- || $t<=$row && $row<=$b && $l<=$col && $col<=$r) {
			$timer->stop;
		} elsif(!$self->{'fastfocus'}) {
			&screen($self, "\t");
		} elsif($row<$t && $col<$l) {
			&screen($self, ":focus down");
			&screen($self, ":focus right");
		} elsif($row<$t && $col>$r) {
			&screen($self, ":focus down");
			&screen($self, ":focus left");
		} elsif($row>$b && $col<$l) {
			&screen($self, ":focus up");
			&screen($self, ":focus right");
		} elsif($row>$b && $col>$r) {
			&screen($self, ":focus up");
			&screen($self, ":focus left");
		} elsif($col<$l) {
			&screen($self, ":focus right");
		} elsif($col>$r) {
			&screen($self, ":focus left");
		} elsif($row<$t) {
			&screen($self, ":focus down");
		} elsif($row>$b) {
			&screen($self, ":focus up");
		}
	})->interval($self->{'latency'});

	return();
}

=head2 Initialization

The B<screen> extension is designed to replace your normal shell with a
L<screen(1)> session.  Therefore, even if requested via a C<-pe> command-line
option or via XResources, it disables itself when the C<-e command ...>
option is sent to L<urxvt(1)>.

=cut

sub on_init {
	my($self)=@_;
	my(@command)=$self->argv();
	my($locale)=$self->locale();
	my($shell)=$self->env()->{'SHELL'};
	my($geometry)=$self->resource('geometry');

	$self->{'grab_row'}=undef;
	$self->{'grab_col'}=undef;

	$self->{'user_rstyle'}=undef;

	#Version dependent control defaults:
	$self->{'vsplit'}=0;
	$self->{'layouts'}=0;
	$self->{'fastfocus'}=0;
	$self->{'silentops'}=0;
	$self->{'so'}='sorendition';
	$self->{'mousetrack'}=0;

	$self->{'nolayout'}=$self->x_resource_boolean('nolayout')
				||   $self->x_resource_boolean('%.screen.nolayout');

	$self->{'fancyButtons'}=$self->x_resource_boolean('fancyButtons')
					||  $self->x_resource_boolean('%.screen.fancyButtons');

	unless($self->{'fancyButtons'} && $locale=~m/UTF-8/i) {
		$self->{'fancyButtons'}=0;
		$self->disable('line_update');
	}

	if($self->x_resource_boolean('noscreen') || $shell!~m/sh$/) {
		$self->disable(@SCREEN_METHODS);
		return();
	}
	foreach my $arg (@command) {
		if($arg eq '-e') {
			$self->disable(@SCREEN_METHODS);
			return();
		}
	}

	#Add a line for the caption bar:
	$geometry=~s/\d+x\K(\d+)/$1+1/e;
	$self->resource('geometry', $geometry);

	if($self->x_resource('latency')) {
		$self->{'latency'}=$self->x_resource('latency')/1000;
	} elsif($self->x_resource('host')) {
		$self->{'latency'}=50/1000;
	} else {
		$self->{'latency'}=10/1000;
	}

	return();
}

=pod

If a session ID is specified via the C<-screenid> command-line option, then it
is used to try to re-attach to the specified session.  If the session does not
exist, then it will be created.  If no C<-screenid> option is used, then
any session re-attach will occur.  If there are no un-attached sessions, then
a new session will be created.

=cut

sub on_child_start {
	my($self, $pid)=@_;
	my($screenid)=$self->x_resource('screenid');
	my($screenexe)=$self->x_resource('screenexe') || 'screen';
	my($host)=$self->x_resource('host');
	my($locale)=$self->locale();
	my(@cmd)=();

	if($host) {
		push(@cmd, 'exec', 'ssh', '-t', $host);
		push(@cmd, 'printf', '"\'\e]777;screen;%c%c %s\a\'" "\`'.$screenexe.' -v\`"', '";"');
	} else {
		push(@cmd, 'printf', '\'\e]777;screen;%c%c %s\a\' `'.$screenexe.' -v`', ';');
	}

	push(@cmd, "LANG=$locale", "LC_ALL=$locale", 'exec', $screenexe);

	if($screenid) {
		$screenid=~s/[^\w:.,+-]/_/g;
		push(@cmd, '-S', $screenid, '-xRR');
	} else {
		push(@cmd, '-RR');
	}

	push(@cmd, '-T', 'xterm');
	push(@cmd, '-U') if($locale=~m/UTF-8/i);
	push(@cmd, '-q');

	$self->tt_paste("unset STY; clear; @cmd\n");

	return();
}

=pod

The title of the window will be set to the value of the C<-title> or C<-name>
L<urxvt(1)> command-line parameters, as usual.  However, if these are absent
and the B<screen> extension is requeted to run on a remote host, the title
of the window will be set to this hostname.

=cut

sub on_configure_notify {
	my($self)=@_;
	my($title)=$self->resource('title');
	my($host)=$self->x_resource('host');

	$self->disable('configure_notify');

	$host=~s/^.*\@//;
	$host=~s/\..*$//;
	$title=$host if($title=~m/urxvt/i);

	$self->{'titlebar'}=urxvt::timer->new()->after(0)->cb(
		sub { $self->cmd_parse("\e]2;$title\a") }
	) if($title);
}

=pod

As L<screen(1)> is being started, the version is sent to the B<screen>
extension.  Based on this verison, features are enabled and disabled.

=cut

sub on_osc_seq_perl {
	my($self, $osc, $resp)=@_;
	my($version);

	if($osc=~m/^screen;Sv (\d+\.\d+)/) {
		$version=$1;
		$self->disable('osc_seq_perl');

		#Version dependent controls:
		$self->{'vsplit'}=1				if($version>4.00);
		$self->{'layouts'}=1			if($version>4.00);
		$self->{'fastfocus'}=1			if($version>4.01);
		$self->{'silentops'}=1			if($version>4.01);
		$self->{'so'}='rendition so'		if($version>4.01);
		$self->{'mousetrack'}=1			if($version>4.01);

		$self->{'timer'}=urxvt::timer->new()->after($self->{'latency'})->cb(
			sub { &init_screen($self) }
		);
	}

	return();
}

=head2 Mouse Actions

Pressing mouse button 1 on the plus (+) sign creates new tabs.

Pressing mouse button 1 on the equal (=) sign opens the menu of common tasks.

Pressing mouse button 1 on the blank area between the last tab name and the
menu character will update the focus to this region.

Pressing mouse button 1 on the name or number of a tab will bring it into
focus in the region selected.  If this tab is already in focus in another
region, that will not change.

Pressing mouse button 1 on the border between two regions which are vertically
split will cause focus in the region to the left of that border.

=cut

sub on_button_press {
	my($self, $event)=@_;

	if($event->{'button'} == 1) {
		&init_screen($self) unless(@{$self->{'regions'}});

		&regions($self);

		if(&caption_click($self, $event)) {
			$self->{'grab_row'}=$event->{'row'};
			&goto($self, $event);
		} elsif(&border_click($self, $event)) {
			$self->{'grab_col'}=$event->{'col'};
			$event->{'col'}--;
			&goto($self, $event);
		}
	}

	return();
}

sub on_button_release {
	my($self, $event)=@_;
	my($row, $col)=($event->{'row'}, $event->{'col'});
	my($start)=$col-length($NT);
	my($line, $id);

	$self->{'grab_row'}=undef;
	$self->{'grab_col'}=undef;
	$self->{'gboxes'}=undef;

	$start=0 if($start<0);

	if($event->{'button'} == 1 && &caption_click($self, $event)) {
		$line=$self->ROW_t($row);

		if($line=~m/^.{$start,$col}(\Q$NT\E|\Q$NTU\E)/) {
			&screen($self, "c");
		} elsif($line=~m/^.{$start,$col}(\Q$MU\E|\Q$MUU\E)/) {
			&menu($self, $event);
		} elsif($line=~m/^.{$col} +(\Q$MU\E|\Q$MUU\E)/) {
			1; #move accomplished in 'on_button_press'
		} elsif($line=~m/^.{$col}-/) {
			&screen($self, '-');
		} else {
			($id)=$line=~m/^.{1,$col}\b(\d+)/;
			&screen($self, ":select $id");
		}
	}

	return();
}

=pod

Selecting the caption bar of a region and dragging it up or down will change
the size of this region.  Selecting the border of a region and dragging it
left or right will resize the retion in that direction.  When region resizing
is in-effect, a small overlay will appear in the top left corner of each
region displaying it's current size.

Selecting inside a window will work as expected to select text and place
it in the primary selection buffer.  However, for windows which do not
span the entire width of the screen, the selection is made in C<rectangle>
mode to allow you to select multiple lines from one region without cruft
from another.

=cut

sub gboxes {
	my($self)=@_;
	my($rstyle)=$self->{'user_rstyle'}|urxvt::RS_Uline;
	my($fmt)=" %3dx%-3d ";
	my($t, $l, $b, $r);

	&regions($self);

	$self->{'gboxes'}=[] unless($self->{'gboxes'});

	foreach my $i (0 .. $#{$self->{'regions'}}) {
		($t, $l, $b, $r)=@{$self->{'regions'}[$i]};

		$self->{'gboxes'}[$i]=$self->overlay($l+1, $t+1, 9, 1, $rstyle, 0);
		$self->{'gboxes'}[$i]->set(0, 0, sprintf($fmt, 1+$r-$l, $b-$t));
	}

}

sub on_motion_notify {
	my($self, $event)=@_;
	my($row, $col)=($event->{'row'}, $event->{'col'});
	my($cols)=$self->ncol()-1;
	my($t, $l, $b, $r);

	if(defined($self->{'grab_row'})) {
		if($row != $self->{'grab_row'}) {
			if($self->{'vsplit'}) {
				&screen($self, sprintf(':resize -v %+d', $row-$self->{'grab_row'}));
			} else {
				&screen($self, sprintf(':resize %+d', $row-$self->{'grab_row'}));
			}
			$self->{'grab_row'}=$row;

			$self->{'draw_gboxes'}=urxvt::timer->new()
										->after($self->{'latency'})
										->cb(sub { &gboxes($self) });
		}
		return(1); #Don't allow selection/marking to occur (aka I got this!)
	} elsif(defined($self->{'grab_col'})) {
		if($col != $self->{'grab_col'}) {
			($t, $l, $b, $r)=&get_region($self, $row, $col);

			&screen($self, sprintf(':resize -h %+d', $col-$self->{'grab_col'}));
			$self->{'grab_col'}=$col;

			$self->{'draw_gboxes'}=urxvt::timer->new()
										->after($self->{'latency'})
										->cb(sub { &gboxes($self) });
		}
		return(1); #Don't allow selection/marking to occur (aka I got this!)
	} else {
		($t, $l, $b, $r)=&get_region($self, $row, $col);
		$self->selection_make($event->{'time'}, ($b>0 && $l>0 || $r<$cols));
	}

	return();
}

=pod

Also for multi-click selection extensions, if they go outside of a region,
the B<screen> extension will cut them to the originating region.

=cut

sub on_sel_extend {
	my($self, $eventtime)=@_;
	my($brow, $bcol, $erow, $ecol);
	my($t, $l, $b, $r);

	$self->selection_make($eventtime);

	($t, $l, $b, $r)=&get_region($self, $self->selection_mark());

	($brow, $bcol)=$self->selection_beg();
	($erow, $ecol)=$self->selection_end();

	$self->selection_beg($brow, $l)	if($bcol<$l);
	$self->selection_end($erow, $r+1)	if($ecol>$r);

	$self->selection_make($eventtime);

	return(1);
}

=head2 Fluff

The C<fancyButtons> command-line option and XResource are available to
update the caption bar icons from ASCII characters to more attractive
Unicode vesions.  If a version of L<screen(1)> were capable of displaying
unicode characters in the caption bar properly while correctly calculating
the line width and a UTF-8 capable locale is set,
then fancy buttons would be used automatically.  These options are used when
L<urxvt(1)> is required to use extra CPU to display Unicode buttons.

=cut

sub on_line_update {
	my($self, $row)=@_;
	my($line)=$self->line($row);
	my($text)=$line->t;

	$line->t($text) if($text=~s/\Q$NT\E/$NTU/g && $text=~s/\Q$MU\E/$MUU/g);
}

=head1 AUTHOR

William Totten < biell @ pobox . com >

=head1 LICENSE

Copyright (C) 2014 William Totten

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.

http://www.gnu.org/licenses/gpl-2.0.html

=cut

