File: [Platon] / thinkpad-status / thinkpad.pl (download)
Revision 1.3, Fri Feb 16 00:25:42 2007 UTC (16 years, 3 months ago) by rajo
Changes since 1.2: +119 -26 lines
Parse basic CPU info, battery info, fan info.
|
#!/usr/bin/perl -w
# vim600: ts=4 fdm=marker fdl=0 fdc=3
#
# thinkpad.pl - show status of ThinkPad laptop
#
# Developed by Lubomir Host 'rajo' <rajo AT platon.sk>
# Copyright (c) 2007 Platon Group, http://platon.sk/
# Licensed under terms of GNU General Public License.
# All rights reserved.
#
# Changelog:
# 2007-02-11 - created
#
# $Platon: thinkpad-status/thinkpad.pl,v 1.2 2007-02-11 15:46:00 rajo Exp $
use strict;
use warnings;
use File::Spec; # portable path manipulations
use Gtk2 '-init'; # auto-initialize Gtk2
use Gtk2::GladeXML;
use Gtk2::SimpleList; # easy wrapper for list views
use Gtk2::Gdk::Keysyms; # keyboard code constants
use Data::Dumper;
use English;
use Time::HiRes qw( gettimeofday );
use POSIX qw(strftime);
use vars qw (
$glade
$x_mainwin $x_status $x_preferences $x_about
$x_refresh_interval
$glib_refresh $refresh_interval $default_update_interval
$x_cpu_scaling_driver $cpu_scaling_driver
$x_cpu_scaling_governor $cpu_scaling_governor
$xx_battery $x_battery @battery
$xx_thermals $x_thermals @thermals
$xx_fan $x_fan @fan
);
$default_update_interval = 1; # 1 second
# Load the UI from the Glade-2 file
my $data = <DATA>;
if ($data !~ m/^\s*<\?xml/m) {
$glade = Gtk2::GladeXML->new("thinkpad.glade");
}
else {
$glade = Gtk2::GladeXML->new_from_buffer($data);
}
# Connect signals magically
$glade->signal_autoconnect_from_package('main');
init_gui();
Gtk2->main; # Start Gtk2 main loop
exit 0;
sub init_gui
{ # {{{
# connect a few widgets we'll access frequently
$x_mainwin = $glade->get_widget('main');
$x_status = $glade->get_widget('statusbar');
$x_preferences = $glade->get_widget('preferences');
$x_about = $glade->get_widget('about');
# refresh interval
$x_refresh_interval = $glade->get_widget('refresh_interval');
# CPU {{{
$x_cpu_scaling_driver = $glade->get_widget('cpu_scaling_driver');
$cpu_scaling_driver = grab_data('/sys/devices/system/cpu/cpu0/cpufreq/scaling_driver');
$x_cpu_scaling_governor = $glade->get_widget('cpu_scaling_governor');
$cpu_scaling_governor = grab_data('/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor');
# }}}
# battery # {{{
$xx_battery = $glade->get_widget('battery');
$x_battery = Gtk2::SimpleList->new_from_treeview(
$xx_battery,
'Param' => 'text',
'Value' => 'text',
);
# set some useful SimpleList properties
$x_battery->set_headers_clickable(0);
foreach ($x_battery->get_columns()) {
$_->set_resizable(1);
$_->set_sizing('grow-only');
}
# }}}
# thermal # {{{
$xx_thermals = $glade->get_widget('thermals');
$x_thermals = Gtk2::SimpleList->new_from_treeview(
$xx_thermals,
'Name' => 'text',
'Temperature' => 'text',
);
# set some useful SimpleList properties
$x_thermals->set_headers_clickable(0);
foreach ($x_thermals->get_columns()) {
$_->set_resizable(1);
$_->set_sizing('grow-only');
}
# }}}
# fan {{{
$xx_fan = $glade->get_widget('fan');
$x_fan = Gtk2::SimpleList->new_from_treeview(
$xx_fan,
'Param' => 'text',
'Value' => 'text',
);
# set some useful SimpleList properties
$x_fan->set_headers_clickable(0);
foreach ($x_fan->get_columns()) {
$_->set_resizable(1);
$_->set_sizing('grow-only');
}
# }}}
# set up a 'refresh' timer
$x_refresh_interval->set_text($default_update_interval);
update_timer($default_update_interval);
make_refresh();
} # }}}
sub make_refresh()
{ # {{{
print_info("make_refresh() called");
refresh_cpu();
refresh_battery();
refresh_thermal();
refresh_fan();
return 1;
} # }}}
# refresh data for tab 'CPU'
sub refresh_cpu()
{ # {{{
$cpu_scaling_driver = grab_data('/sys/devices/system/cpu/cpu0/cpufreq/scaling_driver');
$x_cpu_scaling_driver->set_text($cpu_scaling_driver);
$cpu_scaling_governor = grab_data('/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor');
$x_cpu_scaling_governor->set_text($cpu_scaling_governor);
} # }}}
# refresh data for tab 'Battery'
sub refresh_battery()
{ # {{{
grab_data_by_colon('/proc/acpi/battery/BAT0/state', $x_battery->{data});
} # }}}
# refresh data for tab 'Thermal'
sub refresh_thermal()
{ # {{{
@{$x_thermals->{data}} = ();
open(THERMAL, "</proc/acpi/ibm/thermal") or do { warn "Can't open /proc/acpi/ibm/thermal: $!"; return ; };
@thermals = split(/\s+/, <THERMAL>, 9);
shift @thermals; # remove description
close (THERMAL);
# http://www.thinkwiki.org/wiki/Thermal_sensors
foreach my $desc ('Processor', 'Mini-PCI', 'Harddisk', 'Graphics', 'System battery', 'UltraBay battery', 'System battery', 'UltraBay battery') {
push @{$x_thermals->{data}}, [$desc, shift(@thermals)];
}
} # }}}
# refresh data for tab 'Fan'
sub refresh_fan()
{ # {{{
grab_data_by_colon('/proc/acpi/ibm/fan', $x_fan->{data});
} # }}}
sub grab_data($)
{ # {{{
my ($file) = @_;
my $data;
open(FILE, "<$file") or do { warn "Can't open '$file': $!"; return; };
{
local $/;
$data = <FILE>;
}
close(FILE);
$data =~ s/[^\p{IsPrint}]//g;
return $data;
} # }}}
sub grab_data_by_colon($$)
{ # {{{
my ($file, $arr) = @_;
@$arr = ();
open(COLON, "<$file") or do { warn "Can't open '$file': $!"; return; };
while (my $line = <COLON>) {
chomp $line;
my ($name, $val) = split(/:\s+/, $line, 2);
push @{$arr}, [$name, $val];
}
close(COLON);
} # }}}
sub update_timer($)
{ # {{{
my ($delay) = @_;
return unless $delay; # avoid setting interval to 0
if (defined $glib_refresh) {
Glib::Source->remove($glib_refresh);
}
print_info("update_timer( $delay )");
$glib_refresh = Glib::Timeout->add(1000 * $delay, \&make_refresh);
} # }}}
# Refresh interval in preferences
sub on_refresh_interval_value_changed
{ # {{{
my $w = shift;
update_timer($w->get_text());
} # }}}
sub print_info($;@)
{ # {{{
my ($info, @text) = @_;
printf "[%s PID = $PID ] $0: %s", cur_date(), $info;
print @text if (scalar(@text) > 0);
print "\r\n";
} # }}}
sub cur_date()
{ # {{{
my ($sec, $msec) = Time::HiRes::gettimeofday;
my $time_string = strftime("%Y-%m-%d %X", localtime) . sprintf('.%04d', $msec / 1E4);
return $time_string;
} # }}}
# Glade 2 basic handlers {{{
#----------------------------------------------------------------------
# Signal handlers to match signals defined using Glade-2
#----------------------------------------------------------------------
# Some very simple handlers
sub on_quit_activate {Gtk2->main_quit;}
sub on_prefs_button_clicked {$x_preferences->show_all;}
sub on_preferences_activate {$x_preferences->show_all;}
sub on_about_activate {$x_about->show_all;}
sub on_main_delete_event {Gtk2->main_quit;}
sub on_prefs_cancelbutton_clicked {$x_preferences->hide;}
sub on_about_okbutton_clicked {$x_about->hide;}
#----------------------------------------------------------------------
# Handle dialog 'close' (window-decoration induced close)
# * Just hide the dialog, and tell Gtk not to do anything else
#
sub on_dialog_delete_event {
my $w = shift;
$w->hide;
1; # consume this event!
}
#----------------------------------------------------------------------
# Handle preferencess apply click
#
sub on_prefs_applybutton_clicked {
my $x_context = $x_status->get_context_id('Main');
$x_status->push($x_context, 'Preferences updated');
}
#----------------------------------------------------------------------
# Handle prefs ok click (apply/dismiss dialog)
#
sub on_prefs_okbutton_clicked {
on_prefs_applybutton_clicked();
$x_preferences->hide;
}
# }}}
__DATA__
Platon Group <platon@platon.org> http://platon.org/
|