#!/usr/bin/perl

# Monitor

# Copyright (C) 1999 MandrakeSoft (damien@mandrakesoft.com)
#
# 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, 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

use Gtk;
use lib qw(/usr/lib/libDrakX);
use interactive;
use standalone;
use my_gtk qw(:helpers :wrappers);
#-use Data::Dumper;
use common;
use strict;
use network::netconnect;
use network::tools;
use MDK::Common::Globals "network", qw($in $prefix $connect_file $disconnect_file $connect_prog);

if ("@ARGV" =~ /--help|-h/) {
    print q(Network & Internet connection and monitoring application

--defaultintf interface : show this interface by default
--connect : connect to internet if not already connected
--disconnect : disconnect to internet if already connected
--force : used with (dis)connect : force (dis)connection.
--status : returns 1 if connected 0 otherwise, then exit.
--quiet : don't be interactive. To be used with (dis)connect.
);
    exit(0);
}

if ("@ARGV" =~ /--status/) { print connected(); exit(0) }
my $force = "@ARGV" =~ /--force/;
my $quiet = "@ARGV" =~ /--quiet/;
my $connect = "@ARGV" =~ /--connect/;
my $disconnect = "@ARGV" =~ /--disconnect/;
my ($default_intf) = "@ARGV" =~ /--defaultintf (\w+)/;

if ($force) {
    $connect and system("/etc/sysconfig/network-scripts/net_cnx_up &");
    $disconnect and system("/etc/sysconfig/network-scripts/net_cnx_down &");
    $connect = $disconnect = 0;
}
$quiet and exit(0);
init Gtk;
my $in = 'interactive'->vnew('su', 'default');
$::isEmbedded = ($::XID, $::CCPID) = "@ARGV" =~ /--embedded (\w+) (\w+)/;


my $window1 = $::isEmbedded ? new Gtk::Plug ($::XID) : new Gtk::Window -toplevel;
$window1->signal_connect ( delete_event => sub { Gtk->exit(0); });
$window1->set_position(1);
$window1->set_title(_("Network Monitoring"));
$window1->set_policy(1, 1, 1);
$window1->set_border_width(5);
#$::isEmbedded or $window1->set_usize(580, 320);

my $colorr = my_gtk::gtkcolor(50400, 655, 20000);
my $colort = my_gtk::gtkcolor(55400, 55400, 655);
my $colora = my_gtk::gtkcolor(655, 50400, 655);
my $isconnected=-1;
my @interfaces;
my $monitor = {};
my $netcnx = {};
my $netc = {};
my $intf = {};
my $c_time = 0;
my $ct_tag;
my $style= new Gtk::Style;
$style->font(Gtk::Gdk::Font->fontset_load("-adobe-times-medium-r-normal-*-12-*-75-75-p-*-iso8859-*,*-r-*"));

network::netconnect::load_conf($netcnx, $netc, $intf);
network::netconnect::read_net_conf('', $netcnx, $netc);
my $combo1 = new Gtk::Combo;
$combo1->set_popdown_strings (network::netconnect::get_profiles() );
$combo1->entry->set_text($netcnx->{PROFILE} ? $netcnx->{PROFILE} : "default");
$combo1->entry->set_editable(0);
MDK::Common::Globals::init(
			   in => $in,
			   prefix => '',
			   connect_file => "/etc/sysconfig/network-scripts/net_cnx_up",
			   disconnect_file => "/etc/sysconfig/network-scripts/net_cnx_down",
			   connect_prog => "/etc/sysconfig/network-scripts/net_cnx_pg" );

gtkadd($window1,
       gtkpack_(new Gtk::VBox(0,5),
		0, _("Network Monitoring"),
		1, gtkpack_(new Gtk::HBox(0,5),
			    1, my $notebook = new Gtk::Notebook,
			    0, gtkpack_(new Gtk::VBox(0,5),
					0, gtkadd(gtkset_shadow_type(new Gtk::Frame(_("Settings")), 'etched_out'),
						  gtkpack__(gtkset_border_width(new Gtk::VBox(0,5),5),
							    gtkpack__(new Gtk::HBox(0,0),
								      _("Connection type: "), my $label_cnx_type = new Gtk::Label("")),
							    gtkpack__(new Gtk::HBox(0,0),
								      _("Profile "), $combo1)
							   )
						 ),
					1, gtkadd(gtkset_shadow_type(new Gtk::Frame(_("Statistics")), 'etched_out'),
						  gtkpack__(new Gtk::VBox(0,0),
						  create_packtable({ col_spacings => 1, row_spacings => 1},
						   [ "", "instantaneous" , "average"],
						   [ _("Sending Speed:"), my $label_st = new Gtk::Label(""), my $label_sta=new Gtk::Label("na")],
						   [ _("Receiving Speed:"),my $label_sr= new Gtk::Label(""), my $label_sra=new Gtk::Label("na")],
								  ),
						   gtkpack__(new Gtk::HBox(0,0), "  "._("Connection Time: "), my $label_ct = new Gtk::Label("")),
							   )
						 ),
					0, gtkpack_(new Gtk::HBox(0,5),
						   1, gtksignal_connect(my $button_connect = gtkset_sensitive(new Gtk::Button(), 0), clicked => \&connection),
						   0, new Gtk::VSeparator,
						   0, gtkpack(new Gtk::VBox(0,5),
							      gtksignal_connect(new Gtk::Button(_("Logs")), clicked => sub {
							        -e "/usr/sbin/logdrake"
								  ? system('/usr/sbin/logdrake --file=/var/log/messages &')
								    : system('/usr/X11R6/bin/xvt -e "tail -f /var/log/messages " &')
						 }),
							      gtksignal_connect(my $button_close = new Gtk::Button(_("Close")), clicked => sub { Gtk->exit(0) }),
							     )
						  )
				       )
			   ),
		0, my $statusbar = new Gtk::Statusbar
	       )
      );
$window1->show_all;
$window1->realize;
$combo1->entry->signal_connect( 'changed', sub {
				    network::netconnect::set_profile($netcnx, $combo1->entry->get_text());
				    network::netconnect::load_conf($netcnx, $netc, $intf);
				    network::netconnect::set_net_conf($netcnx, $netc, $intf);
				    network::netconnect::read_net_conf('', $netcnx, $netc);
				});
my $gct = new Gtk::Gdk::GC($window1->window);
$gct->set_foreground($colort);
my $gcr = new Gtk::Gdk::GC($window1->window);
$gcr->set_foreground($colorr);
my $gca = new Gtk::Gdk::GC($window1->window);
$gca->set_foreground($colora);
my ($pix_c_map, $pix_c_mask) = gtkcreate_png("net_c.png");
my ($pix_d_map, $pix_d_mask) = gtkcreate_png("net_d.png");
my ($pix_u_map, $pix_u_mask) = gtkcreate_png("net_u.png");
$button_connect->add(gtkpack__(new Gtk::VBox(0,3),
				   my $pix_c = new Gtk::Pixmap($pix_u_map, $pix_u_mask),
				   my $label_c = new Gtk::Label(_("Wait please"))
				  ));
$statusbar->push(1, _("Wait please, testing your connection..."));
$window1->show_all();
#$window1->set_policy (1, 1, 1);
my $time_tag = Gtk->timeout_add(1000, \&rescan);
my $time_tag2 = Gtk->timeout_add(5000, \&update);

update();
rescan();
while ($isconnected == -1) {
    Gtk->main_iteration while Gtk->events_pending;
}
connection() if ($connect && !$isconnected || $disconnect && $isconnected);
Gtk->main;
Gtk->exit(0);

my $during_connection;
sub connection {
    $during_connection = 1;
    my $isconnected2 = $isconnected;
    $button_connect->set_sensitive(0);
    $button_close->set_sensitive(0);
    $statusbar->pop(1);
    $statusbar->push(1, $isconnected2 ? _("Disconnecting from Internet ") : _("Connecting to Internet "));
    if(!$isconnected2) {
	$c_time = time();
	$ct_tag = Gtk->timeout_add(1000, sub {
				       my ($sec,$min,$hour) = gmtime(time() - $c_time);
				       my $e = sprintf ("%02d:%02d:%02d", $hour, $min, $sec);
				       $label_ct->set($e); 1; });
    } else { Gtk->timeout_remove($ct_tag) }
    my $nb_point=1;
    my $tag = Gtk->timeout_add(100, sub {
				   $statusbar->pop(1);
				   $statusbar->push(1, ($isconnected2 ? _("Disconnecting from Internet ") : _("Connecting to Internet "))
						    . join('', map { "." } (1..$nb_point)));
				   $nb_point++;
				   1;
			       });
    my $netc = {};
    my $tag2 = Gtk->timeout_add(10000, sub {
				    Gtk->timeout_remove($tag);
				    $statusbar->pop(1);
				    $statusbar->push(1, $isconnected2 ? ( $isconnected ?
									  _("Disconnection from Internet failed.") :
									  _("Disconnection from Internet complete.")) :
						     ( $isconnected ?
						       _("Connection complete.") :
						       _("Connection failed.\nVerify your configuration in the Mandrake Control Center."))
						    );
				    my $tag3 = Gtk->timeout_add(10000, sub {
					    $statusbar->pop(1);
					    $statusbar->push(1, $isconnected ? _("Connected") : _("Not connected"));
					    0;
					});
				    $button_connect->set_sensitive(1);
				    $button_close->set_sensitive(1);
				    undef $during_connection;
				    0;
				});
    Gtk->main_iteration while Gtk->events_pending;
    $tag2 = Gtk->timeout_add(1000, sub { system( $isconnected2 ? "/etc/sysconfig/network-scripts/net_cnx_down &" : "/etc/sysconfig/network-scripts/net_cnx_up &"); 0; });
}

sub rescan {
    get_val();
    foreach(@interfaces) {
	my $intf = $_;
	my $recv = $monitor->{$intf}{val}->[0];
	my $transmit = $monitor->{$intf}{val}->[8];
	my $refr = $monitor->{$intf}{referencer};
	my $reft = $monitor->{$intf}{referencet};
	$monitor->{sr} += $recv - $refr;
	$monitor->{st} += $transmit - $reft;

	$monitor->{$intf}{recva} += $recv - $refr;
	$monitor->{$intf}{recvan}++;
	if ($monitor->{$intf}{recvan} > 9) {
	    push(@{$monitor->{$intf}{stack_ra}}, $monitor->{$intf}{recva}/10);
	    $monitor->{$intf}{recva} = $monitor->{$intf}{recvan} = 0;
	} else { push(@{$monitor->{$intf}{stack_ra}}, -1) }
	shift @{$monitor->{$intf}{stack_ra}} if @{$monitor->{$intf}{stack_ra}} > 250;

	push(@{$monitor->{$intf}{stack_r}}, $recv - $refr);
	shift @{$monitor->{$intf}{stack_r}} if @{$monitor->{$intf}{stack_r}} > 250;
	$monitor->{$intf}{labelr}->set(formatXiB($recv - $monitor->{$intf}{initialr}));
	$monitor->{$intf}{referencer} = $recv;

	$monitor->{$intf}{transmita} += $transmit - $reft;
	$monitor->{$intf}{transmitan}++;
	if ($monitor->{$intf}{transmitan} > 9) {
	    push(@{$monitor->{$intf}{stack_ta}}, $monitor->{$intf}{transmita}/10);
	    $monitor->{$intf}{transmita} = $monitor->{$intf}{transmitan} = 0;
	} else { push(@{$monitor->{$intf}{stack_ta}}, -1) }
	shift @{$monitor->{$intf}{stack_ta}} if @{$monitor->{$intf}{stack_ta}} > 250;

	push(@{$monitor->{$intf}{stack_t}}, $transmit - $reft);
	shift @{$monitor->{$intf}{stack_t}} if @{$monitor->{$intf}{stack_t}} > 250;
	$monitor->{$intf}{labelt}->set(formatXiB($transmit - $monitor->{$intf}{initialt}));
	$monitor->{$intf}{referencet} = $transmit;

	draw_monitor($monitor->{$intf});
    }
    $label_sr->set(formatXiB($monitor->{sr}) . "/s");
    $label_st->set(formatXiB($monitor->{st}) . "/s");
    $monitor->{sra} += $monitor->{sr};
    $monitor->{sta} += $monitor->{st};
    $monitor->{nba} ++;
    if($monitor->{nba} > 9) {
	$label_sra->set(formatXiB($monitor->{sra}/10) . "/s");
	$label_sta->set(formatXiB($monitor->{sta}/10) . "/s");
	$monitor->{sra} = 0;
	$monitor->{sta} = 0;
	$monitor->{nba} = 0;
    }
    $label_cnx_type->set($netcnx->{type});
    $monitor->{$_} = 0 foreach ('sr', 'st');
    1;
}

sub get_val {
    my @ret;
    my $a = cat_("/proc/net/dev");
    $a =~ s/^.*?\n.*?\n//;
    $a =~ s/^\s*lo:.*?\n//;
    my @line = split(/\n/, $a);
    foreach(@line) {
	s/\s*(\w*)://;
	my $intf=$1;
	push (@ret,$intf);
	$monitor->{$intf}{val} = [split()];
	$monitor->{$intf}{intf} = $intf;
    }
    @ret;
}

sub change_color {
    my ($color) = @_;
    my $window = new Gtk::Window -toplevel;
    my $doit;
    $window->signal_connect ( delete_event => sub { Gtk->main_quit() });
    $window->set_position(1);
    $window->set_title(_("Color configuration"));
    $window->set_border_width(5);
    gtkadd(gtkset_modal($window,1),
	   gtkpack_(new Gtk::VBox(0,5),
		    1, my $colorsel = new Gtk::ColorSelection,
		    0, gtkadd(gtkset_layout(new Gtk::HButtonBox, -end),
			      gtksignal_connect(new Gtk::Button(_("OK")), clicked => sub { $doit=1; Gtk->main_quit() }),
			      gtksignal_connect(new Gtk::Button(_("Cancel")), clicked => sub { Gtk->main_quit() }),
			     )
		   )
	  );
    $colorsel->set_color($color->red()/65535, $color->green()/65535, $color->blue()/65535, $color->pixel());
    $window->show_all();
    Gtk->main;
    $window->destroy();
    $doit or return $color;
    my (@color) = $colorsel->get_color();
    my_gtk::gtkcolor($color[0]*65535, $color[1]*65535, $color[2]*65535);
}

my $scale;
sub update {
    connected_bg(\$isconnected);
    my @intfs = get_val();
    if($combo1->entry->get_text ne ($netcnx->{PROFILE} ? $netcnx->{PROFILE} : "default")) {
	$combo1->entry->set_text($netcnx->{PROFILE} ? $netcnx->{PROFILE} : "default");
    }
    foreach(@intfs) {
	my $intf = $_;
	if(!member($intf,@interfaces)) {
	    $default_intf = $intf;
	    $monitor->{$intf}{initialr} = $monitor->{$intf}{val}->[0];
	    $monitor->{$intf}{initialt} = $monitor->{$intf}{val}->[8];
	    $monitor->{$intf}{darea} = new Gtk::DrawingArea();
	    $monitor->{$intf}{darea}->set_events(["pointer_motion_mask"]);
	    $notebook->append_page(gtkshow(my $page = gtkpack_(new Gtk::VBox(0,0),
					       0, gtkpack__(gtkset_border_width(new Gtk::HBox(0,0), 5),
							    gtksize($monitor->{$intf}{darea},300, 150)),
					       0, gtkpack_(new Gtk::HBox(0,0),
							    1, gtkpack__(new Gtk::VBox(0,0),
								      gtkpack__(gtkset_border_width(new Gtk::HBox(0,5), 5),
										   gtksignal_connect(my $button_t = gtkset_relief(new Gtk::Button(), 'none'), clicked => sub {
													 $colort = change_color($colort);
													 $gct->set_foreground($colort);
													 $_[0]->draw(undef);
												     }),
										   _("sent: "), $monitor->{$intf}{labelt} = new Gtk::Label("0")),
								      gtkpack__(gtkset_border_width(new Gtk::HBox(0,5), 5),
										   gtksignal_connect(my $button_r = gtkset_relief(new Gtk::Button(), 'none'), clicked => sub {
													 $colorr = change_color($colorr);
													 $gcr->set_foreground($colorr);
													 $_[0]->draw(undef);
												     }),
										   _("received: "), $monitor->{$intf}{labelr} = new Gtk::Label("0")),
								      gtkpack__(gtkset_border_width(new Gtk::HBox(0,5), 5),
										   gtksignal_connect(my $button_a = gtkset_relief(new Gtk::Button(), 'none'), clicked => sub {
													 $colora = change_color($colora);
													 $gca->set_foreground($colora);
													 $_[0]->draw(undef);
												     }),
										   _("average"))
								     ),
							    0, gtkpack__(gtkset_border_width(new Gtk::VBox(0,0), 5),
							      gtkadd(gtkset_shadow_type(new Gtk::Frame(_("Local measure")), 'etched_out'),
								     gtkpack__(gtkset_border_width(new Gtk::VBox(0,0), 5),
									       gtkpack__(new Gtk::HBox(0,0),
											 _('sent: '),
											 my $measure_t = new Gtk::Label("0")
											),
									       gtkpack__(new Gtk::HBox(0,0),
											 _('received: '),
											 my $measure_r = new Gtk::Label("0")
											)
									      )
									)
									)
							  )
					       )),
				   new Gtk::Label($intf));
	    foreach my $i ([$button_t, $gct],[$button_r, $gcr],[$button_a, $gca]) {
		$i->[0]->add(gtksignal_connect(gtkshow(gtksize(gtkset_usize(new Gtk::DrawingArea(), 10, 10), 10, 10)), expose_event => sub{ $_[0]->window->draw_rectangle ($i->[1], 1, 0, 0, 10, 10)} ));
	    }
	    $notebook->set_page($notebook->page_num($page));
	    $monitor->{$intf}{page}=($notebook->page_num($page));
	    $monitor->{$intf}{pixmap_db} = new Gtk::Gdk::Pixmap($monitor->{$intf}{darea}->window, 300, 150);
	    $monitor->{$intf}{referencer} = $monitor->{$intf}{val}->[0];
	    $monitor->{$intf}{referencet} = $monitor->{$intf}{val}->[8];
	    $monitor->{$intf}{pixmap_db}->draw_rectangle ($monitor->{$intf}{darea}->style->black_gc, 1, 0, 0, 300, 150);
	    $monitor->{$intf}{darea}->signal_connect( motion_notify_event =>
					      sub { my ($w, $e) = @_;
						    my $x = $e->{'x'} - 50;
						    my $y = $e->{'y'};
						    my $received = $x >= 0 ? $monitor->{$intf}{stack_r}[$x] : 0;
						    my $transmitted = $x >= 0 ? $monitor->{$intf}{stack_t}[$x] : 0;
						    my $type;
						    $y * $scale / 150 < $transmitted and $type = _('transmitted');
						    (150 - $y) * $scale / 150 < $received and $type = _('received');
						    $measure_r->set(formatXiB($received));
						    $measure_t->set(formatXiB($transmitted));
						});
	    $monitor->{$intf}{darea}->signal_connect( expose_event => sub {
					$monitor->{$intf}{darea}->window->draw_pixmap ($monitor->{$intf}{darea}->style->bg_gc('normal'),
								     $monitor->{$intf}{pixmap_db}, 0, 0, 0, 0, 300, 150);
				    });
	}
    }
    foreach(@interfaces) {
	my $intf = $_;
	if(!member($intf,@intfs)) {
	    $notebook->remove_page($monitor->{$intf}{page});
	}
    }
    @interfaces = @intfs;
    my $netc={};
    if ($isconnected != -1 && !$during_connection) {
	$button_connect->set_sensitive(1);
	$label_c->set($isconnected ? _("Disconnect") : _("Connect"));
	$statusbar->pop(1);
	$statusbar->push(1, $isconnected ? _("Connected") : _("Not connected"));
	$isconnected ? $pix_c->set($pix_c_map, $pix_c_mask) : $pix_c->set($pix_d_map, $pix_d_mask);
    }
    if (!(-e $connect_file && -e $disconnect_file)) {
	$button_connect->set_sensitive(0);
	$label_c->set("No internet connection configured");
    }
    1;
}

sub draw_monitor {
    my ($o) = @_;
    defined $o->{darea} or return;
    $o->{pixmap_db}->draw_rectangle ($o->{darea}->style->black_gc, 1, 0, 0, 300, 150);
    my $maxr = 0;
    foreach (@{$o->{stack_r}}) { $maxr = $_ if $_>$maxr }
    my $maxt = 0;
    foreach (@{$o->{stack_t}}) { $maxt = $_ if $_>$maxt }
    my $ech = $maxr + $maxt;
    $ech == 0 and $ech = 1;
    $scale = $ech;
    my $step=49;
    foreach (@{$o->{stack_t}}) {
	$o->{pixmap_db}->draw_rectangle($gct, 1, $step, 0, 1, $_*150/$ech);
	$step++;
    }
    $step=49;
    my ($av1, $av2, $last_a);
    foreach (@{$o->{stack_ta}}) {
	if($_ != -1) {
	    if( !defined $av1) { $av1 = $_ } else { defined $av2 or $av2 = $_ }
	    if ($av1 && $av2) {
		$o->{pixmap_db}->draw_line($gca, $step-15, $av1*150/$ech, $step-5, $av2*150/$ech);
		$av1 = $av2;
		undef $av2;
		$last_a = $step-50;
	    }
	}
	$step++;
    }
    $step=49;
    foreach (@{$o->{stack_r}}) {
	$o->{pixmap_db}->draw_rectangle($gcr, 1, $step, 151-$_*150/$ech, 1, $_*150/$ech);
	$step++;
    }
    $step=49;
    ($av1, $av2) = undef;
    foreach (@{$o->{stack_ra}}) {
	if($_ != -1) {
	    if(!defined $av1) { $av1 = $_ } else { defined $av2 or $av2 = $_ }
	    if ((defined $av1) && (defined $av2)) {
		$o->{pixmap_db}->draw_line($gca, $step-15, 151-$av1*150/$ech, $step-5, 151-$av2*150/$ech);
		$av1 = $av2;
		undef $av2;
	    }
	}
	$step++;
    }

    my $switch = 1;
    my $gcl = new Gtk::Gdk::GC($o->{darea}->window);
    $gcl->set_foreground($o->{darea}->window->get_colormap->color_white());
    $gcl->set_line_attributes (1, 'on-off-dash', 'not-last', 'round');
    for (my $i = 30;$i<=120;$i+=30) {
	$o->{pixmap_db}->draw_line($gcl, 50, $i, 300, $i);
	my ($gc2, $text);
	my ($dif1, $dif2);
	if ($last_a) {
	    $dif1 = abs(150-@{$o->{stack_ra}}[$last_a]*150/$ech - $i);
	    $dif2 = abs(@{$o->{stack_ta}}[$last_a]*150/$ech - $i);
	} else {
	    $dif1 = abs(150-@{$o->{stack_r}}[@{$o->{stack_r}}-1]*150/$ech - $i);
	    $dif2 = abs(@{$o->{stack_t}}[@{$o->{stack_t}}-1]*150/$ech - $i);
	}
	if ($dif1 < $dif2) {
	    $text = formatXiB((150-$i)*$ech/150);
	    $gc2=$gcr;
	    my $x_l=5;
	    if ($i > 30 && $switch) {
		$o->{pixmap_db}->draw_line($gct, $x_l, 0, $x_l, $i-30);
		$o->{pixmap_db}->draw_line($gct, $x_l-1, 0, $x_l-1, $i-30);
		$o->{pixmap_db}->draw_line($gct, $x_l+1, 0, $x_l+1, $i-30);
		$o->{pixmap_db}->draw_polygon($gct, 1, $x_l-4, $i-30, $x_l+5, $i-30, $x_l, $i-25);
	    }
	    if ($switch) {
		$o->{pixmap_db}->draw_line($gcr, $x_l, 150, $x_l, $i);
		$o->{pixmap_db}->draw_line($gcr, $x_l-1, 150, $x_l-1, $i);
		$o->{pixmap_db}->draw_line($gcr, $x_l+1, 150, $x_l+1, $i);
		$o->{pixmap_db}->draw_polygon($gcr, 1, $x_l-5, $i, $x_l+5, $i, $x_l, $i-6);
	    }
	    undef $switch;
	} else {
	    $text = formatXiB($i*$ech/150);
	    $gc2=$gct;
	}
	my $w = $style->font->string_width($text);
	$o->{pixmap_db}->draw_string($style->font, $gc2, 45-$w, $i+5, ($text) );
    }
    $o->{darea}->draw(undef);
}