Hello everyone,
Some time ago I have posted a patch to the tabbed extension which I got
no reply to. I believe this is an useful feature everyone can benefit
from and as such would like to hear it in mainstream or at least some
comments why not.
The patch changes the tabbed extension adding the following features:
1. time dependent activity marks (the mark displayed next to the tab
number depends on the time since last activity in given tab);
2. the "[NEW]" button can be disabled by setting new-button resource to
false;
3. tab's title is displayed after last button (unless title resource is
false). This is handy if you have terminal with no window
decorations. Colours can be configured via title-fg and title-bg;
4. tab bar can be hidden if there is only one tab opened (Alexey
Semenko's <asemenko at gmail.com> patch);
5. tabs are indexed in hex starting with zero -- less space occupied if
you have 16 tabs opened; and
6. (as a minor modification) final pipe character is removed (unless
title is displayed).
--
Best regards, _ _
.o. | Liege of Serenly Enlightened Majesty of o' \,=./ `o
..o | Computer Science, Michal "mina86" Nazarewicz (o o)
ooo +--<mina86-tlen.pl>--<jid:mina86-jabber.org>--ooO--(_)--Ooo--
Index: doc/rxvtperl.3.man.in
===================================================================
RCS file: /schmorpforge/rxvt-unicode/doc/rxvtperl.3.man.in,v
retrieving revision 1.68
diff -u -r1.68 rxvtperl.3.man.in
--- doc/rxvtperl.3.man.in 16 Mar 2010 00:54:46 -0000 1.68
+++ doc/rxvtperl.3.man.in 29 Apr 2010 10:04:10 -0000
@@ -376,15 +376,43 @@
\&\fBShift-Right\fR will switch to the tab left or right of the current one,
while \fBShift-Down\fR creates a new tab.
.Sp
+Whenever there's an activity on a\ hidden tab a\ symbol (asterisk ny
+default) will appear next to tab's number. This mark will change
+depending on the time since last activity (letting you see if
+compilation has finished for instance).
+.Sp
+Moreover, after all the tabs numbers current's tab's title (the thing
+usually visible in window's title bar) is displayed.
+.Sp
The tabbar itself can be configured similarly to a normal terminal, but
-with a resource class of \f(CW\*(C`URxvt.tabbed\*(C'\fR. In addition, it supports the
-following four resources (shown with defaults):
+with a resource class of \f(CW\*(C`URxvt.tabbed\*(C'\fR.
+.Sp
+Setting the "URxvt.tabbed.new-button" resource to "false" will hide
+the \*(L"[\s-1NEW\s0]\*(R" button. Setting the
+"URxvt.tabbat.autohide" resource to "true" will make the top bar hide
+if there is only one tab. Setting the "URxvt.tabbed.title" resource
+to "false" will hide the terminal's title from the top bar.
+.Sp
+The activity marks can be configured as well as via
+"URxvt.tabbed.tabbar-timeouts" resource. It's format is:
+.Sp
+.Vb 4
+\& ( <time> ":" <char> ":" )* <time> ":" <char> ":"
+.Ve
+.Sp
+where <time> is timeout in seconds and <char> is a single activity
+character. The default is "16:.:8:::4:+".
+.Sp
+In addition, it supports the following resources (shown with defaults)
+for specifying colours of various elements:
.Sp
.Vb 4
\& URxvt.tabbed.tabbar\-fg: <colour\-index, default 3>
\& URxvt.tabbed.tabbar\-bg: <colour\-index, default 0>
\& URxvt.tabbed.tab\-fg: <colour\-index, default 0>
\& URxvt.tabbed.tab\-bg: <colour\-index, default 1>
+\& URxvt.tabbed.title\-fg: <colour\-index, default 2>
+\& URxvt.tabbed.title\-bg: <colour\-index, default 0>
.Ve
.Sp
See \fI\s-1COLOR\s0 \s-1AND\s0 \s-1GRAPHICS\s0\fR in the @@RXVT_NAME@@(1) manpage for valid
Index: src/perl/tabbed
===================================================================
RCS file: /schmorpforge/rxvt-unicode/src/perl/tabbed,v
retrieving revision 1.25
diff -u -r1.25 tabbed
--- src/perl/tabbed 15 Jun 2008 14:54:44 -0000 1.25
+++ src/perl/tabbed 29 Apr 2010 10:04:11 -0000
@@ -1,40 +1,106 @@
#! perl
+##
+## Tabbed plugin for rxvt-unicode
+## Modified by Michal Nazarewicz (mina86/AT/mina86.com)
+##
+## The following has been added:
+##
+## 1. Depending on time of last activity, activity character differs.
+## By default, after 4 seconds an asterisk becomes a plus sing,
+## after next 4 it becomes a colon, and finally, after another 8
+## seconds it becomes a dot. This can be configured via
+## tabbar-timeouts resource. It's format is:
+##
+## ( <timeout> ":" <character> ":" )* <timeout> ":" <character> ":"
+##
+## where <timeout> is timeout in seconds and <character> is
+## a single activity character.
+##
+## 2. The "[NEW]" button can be disabled (who on Earth uses mouse to
+## create new tab anyways?) by setting new-button resource to
+## false.
+##
+## 3. tab's title is displayed after last button unless title resource
+## is set to false. This is handy if you have terminal with no
+## window decorations. Colours can be configured via title-fg and
+## title-bg.
+##
+## 4. Incorporated Alexey Semenko <asemenko at gmail.com> patch adding
+## autohide resource. If it's true tab bar is hidden if there is
+## no more then one tab opened.
+##
+## 5. Tabs are indexed in hex starting with zero. :] If you're such
+## a geek to use urxvt it shouldn't be a problem for you and it
+## saves few character when many tabs are opened.
+##
+## 6. As a minor modification: Final pipe character is removed (unless
+## title is displayed). This make tab bar look nicer.
+##
+
+
+sub tab_activity_mark ($$) {
+ my ($self, $tab) = @_;
+ return ' ' unless defined $tab->{lastActivity};
+ return ' ' if $tab == $self->{cur};
+ if (defined $self->{timeouts}) {
+ my $diff = int urxvt::NOW - $tab->{lastActivity};
+ for my $spec (@{ $self->{timeouts} }) {
+ return $spec->[1] if $diff > $spec->[0];
+ }
+ }
+ '*';
+}
+
+
sub refresh {
my ($self) = @_;
+ # autohide makes it zero
+ return unless $self->{tabheight};
+
my $ncol = $self->ncol;
my $text = " " x $ncol;
my $rend = [($self->{rs_tabbar}) x $ncol];
- my @ofs;
-
- substr $text, 0, 7, "[NEW] |";
- @$rend[0 .. 5] = ($self->{rs_tab}) x 6;
- push @ofs, [0, 6, sub { $_[0]->new_tab }];
+ my ($ofs, $idx, @ofs) = (0, 0);
- my $ofs = 7;
- my $idx = 0;
+ if ($self->{new_button}) {
+ substr $text, 0, 7, "[NEW] |";
+ @$rend[0 .. 5] = ($self->{rs_tab}) x 6;
+ push @ofs, [0, 6, -1 ];
+ $ofs = 7;
+ }
for my $tab (@{ $self->{tabs} }) {
- $idx++;
-
- my $act = $tab->{activity} && $tab != $self->{cur}
- ? "*" : " ";
-
- my $txt = "$act$idx$act";
+ my $act = $self->tab_activity_mark($tab);
+ my $txt = sprintf "%s%x%s", $act, $idx, $act;
my $len = length $txt;
substr $text, $ofs, $len + 1, "$txt|";
@$rend[$ofs .. $ofs + $len - 1] = ($self->{rs_tab}) x $len
if $tab == $self->{cur};
- push @ofs, [ $ofs, $ofs + $len, sub { $_[0]->make_current ($tab) } ];
-
+ push @ofs, [ $ofs, $ofs + $len, $idx ];
+ ++$idx;
$ofs += $len + 1;
}
+ substr $text, --$ofs, 1, ' '; # remove last '|'
+
+ if ($self->{tab_title} && $ofs + 3 < $ncol) {
+ my $term = $self->{term};
+ my @str = $term->XGetWindowProperty($term->parent, $self->{tab_title});
+ if (@str && $str[2]) {
+ my $str = '| ' . $str[2];
+ my $len = length $str;
+ $len = $ncol - $ofs if $ofs + $len > $ncol;
+ substr $text, $ofs, $len, substr $str, 0, $len;
+ @$rend[$ofs + 2 .. $ofs + $len - 1] = ($self->{rs_title}) x ($len - 2);
+ }
+ }
+
$self->{tabofs} = \...@ofs;
$self->ROW_t (0, $text, 0, 0, $ncol);
@@ -48,6 +114,9 @@
my $offset = $self->fheight;
+ $self->{tabheight} = $self->{maxtabheight}
+ unless $self->{autohide} && !(defined $self->{tabs} && @{ $self->{tabs} });
+
# save a backlink to us, make sure tabbed is inactive
push @urxvt::TERM_INIT, sub {
my ($term) = @_;
@@ -68,8 +137,7 @@
my $term = new urxvt::term
$self->env, $urxvt::RXVTNAME,
-embed => $self->parent,
- @argv,
- ;
+ @argv;
}
sub configure {
@@ -90,11 +158,6 @@
);
}
-sub on_resize_all_windows {
- my ($self, $width, $height) = @_;
-
- 1
-}
sub copy_properties {
my ($self) = @_;
@@ -134,7 +197,7 @@
my ($self, $tab) = @_;
if (my $cur = $self->{cur}) {
- delete $cur->{activity};
+ delete $cur->{lastActivity};
$cur->XUnmapWindow ($cur->parent) if $cur->mapped;
$cur->focus_out;
}
@@ -148,7 +211,7 @@
$tab->focus_in if $self->focus;
$tab->XMapWindow ($tab->parent);
- delete $tab->{activity};
+ delete $tab->{lastActivity};
$self->refresh;
()
@@ -180,13 +243,7 @@
sub on_key_release {
my ($self, $event) = @_;
-
$self->{cur}->key_release ($event->{state}, $event->{keycode}, $event->{time});
-
- 1
-}
-
-sub on_button_press {
1
}
@@ -194,18 +251,20 @@
my ($self, $event) = @_;
if ($event->{row} == 0) {
+ my $col = $event->{col};
for my $button (@{ $self->{tabofs} }) {
- $button->[2]->($self, $event)
- if $event->{col} >= $button->[0]
- && $event->{col} < $button->[1];
+ last if $col < $button->[0];
+ next unless $col <= $button->[1];
+ if ($button->[2] == -1) {
+ $self->new_tab;
+ } else {
+ $self->make_current($self->{tabs}[$button->[2]]);
+ }
}
+ return 1;
}
- 1
-}
-
-sub on_motion_notify {
- 1
+ ()
}
sub on_init {
@@ -223,14 +282,40 @@
my $bg = $self->x_resource ("tabbar-bg");
my $tabfg = $self->x_resource ("tab-fg");
my $tabbg = $self->x_resource ("tab-bg");
+ my $titfg = $self->x_resource ("title-fg");
+ my $titbg = $self->x_resource ("title-bg");
defined $fg or $fg = 3;
defined $bg or $bg = 0;
defined $tabfg or $tabfg = 0;
defined $tabbg or $tabbg = 1;
+ defined $titfg or $titfg = 2;
+ defined $titbg or $titbg = 0;
$self->{rs_tabbar} = urxvt::SET_COLOR (urxvt::DEFAULT_RSTYLE, $fg + 2, $bg + 2);
$self->{rs_tab} = urxvt::SET_COLOR (urxvt::DEFAULT_RSTYLE, $tabfg + 2, $tabbg + 2);
+ $self->{rs_title} = urxvt::SET_COLOR (urxvt::DEFAULT_RSTYLE, $titfg + 2, $titbg + 2);
+
+
+ my $timeouts = $self->x_resource ("tabbar-timeouts");
+ $timeouts = '16:.:8:::4:+' unless defined $timeouts;
+ if ($timeouts ne '') {
+ my @timeouts;
+ while ($timeouts =~ /^(\d+):(.)(?::(.*))?$/) {
+ push @timeouts, [ int $1, $2 ];
+ $timeouts = defined $3 ? $3 : '';
+ }
+ if (@timeouts) {
+ $self->{timeouts} = [ sort { $b->[0] <=> $a-> [0] } @timeouts ];
+ }
+ }
+
+ $self->{new_button} =
+ ($self->x_resource ('new-button') or 'true') !~ /^(?:false|0|no)/i;
+ $self->{tab_title} =
+ ($self->x_resource ('title') or 'true') !~ /^(?:false|0|no)/i;
+ $self->{autohide} =
+ ($self->x_resource ('autohide') or 'false') !~ /^(?:false|0|no)/i;
()
}
@@ -238,7 +323,8 @@
sub on_start {
my ($self) = @_;
- $self->{tabheight} = $self->int_bwidth + $self->fheight + $self->lineSpace;
+ $self->{maxtabheight} = $self->int_bwidth + $self->fheight + $self->lineSpace;
+ $self->{tabheight} = $self->{autohide} ? 0 : $self->{maxtabheight};
$self->cmd_parse ("\033[?25l");
@@ -248,8 +334,20 @@
shift @argv;
} while @argv && $argv[0] ne "-e";
+ if ($self->{tab_title}) {
+ $self->{tab_title} = $self->{term}->XInternAtom("WM_NAME", 1);
+ }
+
$self->new_tab (@argv);
+ if (defined $self->{timeouts}) {
+ my $interval = ($self->{timeout...@{ $self->{timeouts} } - 1]->[0]);
+ $interval = int($interval / 4);
+ $self->{timer} = urxvt::timer->new
+ ->interval($interval < 1 ? 1 : $interval)
+ ->cb ( sub { $self->refresh; } );
+ }
+
()
}
@@ -287,6 +385,7 @@
my ($self, $tab) = @_;
$self->{tabs} = [ grep $_ != $tab, @{ $self->{tabs} } ];
+ $self->{tabheight} = 0 if $self->{autohide} && @{ $self->{tabs} } <= 1;
if (@{ $self->{tabs} }) {
if ($self->{cur} == $tab) {
@@ -308,30 +407,29 @@
if ($event->{state} & urxvt::ShiftMask) {
if ($keysym == 0xff51 || $keysym == 0xff53) {
- my ($idx) = grep $self->{tabs}[$_] == $tab, 0 .. $#{ $self->{tabs} };
-
- --$idx if $keysym == 0xff51;
- ++$idx if $keysym == 0xff53;
-
- $self->make_current ($self->{tabs}[$idx % @{ $self->{tabs}}]);
-
+ if (@{ $self->{tabs} } > 1) {
+ my $idx = 0;
+ ++$idx while $self->{tabs}[$idx] != $tab;
+ $idx += $keysym - 0xff52;
+ $self->make_current ($self->{tabs}[$idx % @{ $self->{tabs}}]);
+ }
return 1;
} elsif ($keysym == 0xff54) {
$self->new_tab;
return 1;
}
- }
- elsif ($event->{state} & urxvt::ControlMask) {
+ } elsif ($event->{state} & urxvt::ControlMask) {
if ($keysym == 0xff51 || $keysym == 0xff53) {
- my ($idx1) = grep $self->{tabs}[$_] == $tab, 0 .. $#{ $self->{tabs} };
- my $idx2 = ($idx1 + ($keysym == 0xff51 ? -1 : +1)) % @{ $self->{tabs} };
-
- ($self->{tabs}[$idx1], $self->{tabs}[$idx2]) =
- ($self->{tabs}[$idx2], $self->{tabs}[$idx1]);
-
- $self->make_current ($self->{tabs}[$idx2]);
-
+ if (@{ $self->{tabs} } > 1) {
+ my $idx1 = 0;
+ ++$idx1 while $self->{tabs}[$idx1] != $tab;
+ my $idx2 = ($idx1 + $keysym - 0xff52) % @{ $self->{tabs} };
+
+ ($self->{tabs}[$idx1], $self->{tabs}[$idx2]) =
+ ($self->{tabs}[$idx2], $self->{tabs}[$idx1]);
+ $self->make_current ($self->{tabs}[$idx2]);
+ }
return 1;
}
}
@@ -348,10 +446,13 @@
()
}
-sub tab_activity {
+sub tab_add_lines {
my ($self, $tab) = @_;
- $self->refresh;
+ my $mark = $self->tab_activity_mark($tab);
+ $tab->{lastActivity} = int urxvt::NOW;
+ $self->refresh if $mark ne $self->tab_activity_mark($tab);
+ ()
}
package urxvt::ext::tabbed::tab;
@@ -360,7 +461,7 @@
# simply proxies all interesting calls back to the tabbed class.
{
- for my $hook qw(start destroy key_press property_notify) {
+ for my $hook qw(start destroy key_press property_notify add_lines) {
eval qq{
sub on_$hook {
my \$parent = \$_[0]{term}{parent}
@@ -371,11 +472,3 @@
die if $@;
}
}
-
-sub on_add_lines {
- $_[0]->{activity}++
- or $_[0]{term}{parent}->tab_activity ($_[0]);
- ()
-}
-
-
_______________________________________________
rxvt-unicode mailing list
[email protected]
http://lists.schmorp.de/cgi-bin/mailman/listinfo/rxvt-unicode