#!/usr/bin/perl -w
# quick apps to manage freq throttle of laptop CPU
# aginies ateuh mdk . com
# devel release based on net_applet

my $version = "0.5";
use lib qw(/usr/lib/libDrakX);
use strict;
use common;
use c;
use standalone;
use Gtk2::TrayIcon;
use ugtk2 qw(:create :wrappers :helpers :dialogs);

my ($eventbox, $img);
my ($current_state, $menu, $timeout);
my $prog = "cpu_applet";
my $onstartupfile = "$ENV{HOME}/.cpu_applet";
add_icon_path("/usr/share/$prog");
is_running($prog) and die "$prog already running\n";

# directory and file needed
my $CPUTH = "/proc/acpi/processor/CPU0/throttling";
my $CPU = "/sys/devices/system/cpu/cpu0/cpufreq";
my $maxfreq = cat_("$CPU/scaling_max_freq");
my $minfreq = cat_("$CPU/scaling_min_freq");


# be sure needed /sys and /proc/acpi are present
if (! -d $CPU) {
  err_dialog(N("Error!"), N("missing cpufreq dir ... Please be sure ACPI is supported on our laptop.")) and !$::testing && die;
}

if (! -e $CPUTH) {
  err_dialog(N("Error!"), N("missing %s ... Please be sure throttling is supported on our laptop."), $CPUTH) and !$::testing && die;
}

# must be a sudo users
if (! -e $onstartupfile) {
  err_dialog(N("Warning"), N("You must be a sudo users to Throttle and change cpufreq. You have been informed."));
}

my %list_th_code = (
                     '0' => "100%",
		     '1' => "75%",
		     '2' => "50%",
		     '3' => "25%",
		    );

my %list_th_percent = (
		       '100%' => "0",
		       '75%' => "1",
		       '50%' => "2",
		       '25%' => "3",
		      );

my @list_freq = split(/\s/, cat_("$CPU/scaling_available_frequencies"));
my @list_th = qw(100% 75% 50% 25%);


# function needed
sub get_throttle {
  print "get throttle running\n";
  my @t = grep { /\*T\d:/ } cat_($CPUTH);
  foreach (@t) {
    if ($_) {
      my ($state) = /\*T(\d)/;
      $state and print "throttle is set to: $state\n";
      my $percent = $list_th_code{$state};
      return chomp_($percent);
    }
  }
}

sub get_cpu_freq {
  print "get cpu freq\n";
  my $cfreq = cat_("$CPU/scaling_cur_freq");
  print "actual CPU freq: $cfreq";
  return chomp_($cfreq);
}

sub set_freq {
  my ($freq) = @_;
  print "set CPU freq to: $freq\n";
  system("sudo sh -c 'echo $freq > $CPU/scaling_setspeed'");
}

sub set_throttle {
  my ($th) = @_;
  print "set throttle to $th\n";
  system("sudo sh -c 'echo $th > $CPUTH'");
}

sub set_userspace {
  if (! any { /userspace/ } cat_("$CPU/scaling_governor")) {
    print "set userspace governor\n";
    system("sudo sh -c 'echo userspace > $CPU/scaling_governor'");
  }
}

sub error_acpi {
  my ($bacpi) = @_;
  err_dialog(N("Error!"), N("missing %s ... Please be sure throttling is supported on our laptop."), $bacpi) and !$::testing && die;
}

sub get_batt {
# using acpi tools
#      Battery 1: discharging, 87%, 03:10:30 remaining
  my $bacpi = "/usr/bin/acpi";
  print "getting acpi info on battery";
  if (-e $bacpi) {
    my @cmd = `$bacpi -b`;
    foreach (@cmd) {
      my ($percent, $time) = /\s+Battery\s\d\:.*(\d\d)\%,\s(\d\d\:\d\d:\d\d)/;
      $percent and return $percent;
      $time and return $time;
    }
  } else { error_acpi($bacpi) }
}

sub get_batt2 {
# using acpitools
#  Battery #1     : discharging, 70.00%, 02:44:03
  my $bacpi = "/usr/bin/acpitool";
  if (-e $bacpi) {
    print "getting acpitool info on battery";
    my @cmd = `$bacpi -b`;
    foreach (@cmd) {
      my ($percent, $time) = /\s+Battery\s#\d\s+\:.*(\d\d\.\d\d)\%,\s(\d\d\:\d\d:\d\d)/;
      $percent and print "percent: $percent\n";
      $time and print "time: $time\n";
    }
  } else { error_acpi($bacpi) }
}

sub display_info {
  my @info = chomp_(`acpi -V `);
  info_dialog("ACPI Info",
	      gtkpack_(gtkset_border_width(Gtk2::VBox->new, 3),
		       0, @info,
		      ),
	     ),
}

######################
## applet definition
my %appletstate = (
		   minlife => {
			       colour => [ 'cpufreq-100' ],
			       menu => [ 'mincpu', 'mediumcpu', 'intercpu', 'cpufreq', 'cputhrottle' ],
			       tt => [ N_("Max CPU and Throttle, min lifetime") ],
			      },
		   interlife => {
				  colour => [ 'cpufreq-75' ],
				  menu => [ 'mincpu', 'intercpu', 'maxcpu', 'cpufreq', 'cputhrottle' ],
				  tt => [ N_("75\% CPU and Throttle, Intermediate lifetime") ],
				 },
		   mediumlife => {
				  colour => [ 'cpufreq-50' ],
				  menu => [ 'mincpu', 'intercpu', 'maxcpu', 'cpufreq', 'cputhrottle' ],
				  tt => [ N_("Medium CPU and Throttle, medium lifetime") ],
				 },
		   maxlife => {
			       colour => [ 'cpufreq-25' ],
			       menu => [ 'mediumcpu', 'intercpu', 'maxcpu', 'cpufreq', 'cputhrottle' ],
			       tt => [ N_("Min CPU and Throttle, max lifetime") ],
			      },
		   manuallife => {
				  colour => [ 'cpufreq-na' ],
				  menu => [ 'mincpu', 'mediumcpu', 'intercpu', 'maxcpu', 'cpufreq', 'cputhrottle' ],
				  tt => [ N_("Custom CPU and Throttle") ],
				 },
		  );

my %actions = (
               'maxcpu' => { name => sub { N("Min Lifetime") }, launch => sub {
			       set_throttle("0");
			       set_freq($list_freq[0]);
			       go2State("minlife", "");
			     } },
               'mediumcpu' => { name => sub { N("Medium Lifetime") }, launch => sub {
				  set_throttle("2");
				  set_freq($list_freq[3]);
				  go2State("mediumlife", "");
				} },
               'intercpu' => { name => sub { N("Intermediate Lifetime") }, launch => sub {
			       set_throttle("1");
			       set_freq($list_freq[2]);
			       go2State("interlife", "");
			     } },
	       'mincpu' => { name => N("Max Lifetime"), launch => sub {
			       # i know max throttle is 3 but to slow... so using 50%
			       set_throttle("2");
			       set_freq($list_freq[-1]);
			       go2State("maxlife", "");
			     } },
	       cpufreq => {
			   name => N("Choose CPU freq"),
			   choices => sub { @list_freq },
			   choice_selected => sub { $_[0] eq get_cpu_freq },
			   launch => sub {
			     set_freq($_[0]);
			     go2State("manuallife", "");
			   }
			  },
	       cputhrottle => {
			       name => N("Choose Throttle"),
			       choices => sub { @list_th },
			       choice_selected => sub { $_[0] eq get_throttle },
			       launch => sub {
				 set_throttle($_[0]);
				 go2State("manuallife", "");
			       } },
	      );


sub mainQuit() {
  Glib::Source->remove($timeout) if $timeout;
  Gtk2->main_quit;
}

sub go2State {
  my ($state_type, $battery) = @_;
  if ($current_state ne $state_type) {
    $current_state = $state_type;
    $menu and $menu->destroy;
    $menu = setState($state_type, $battery);
  }
}

sub setState {
  my ($state_type, $battery) = @_;
  my $checkmi;
  my $arr = $appletstate{$state_type}{menu};
  my $tmp = gtkcreate_pixbuf($appletstate{$state_type}{colour}[0]);
  $img->set_from_pixbuf($tmp);
  gtkset_tip(Gtk2::Tooltips->new, $eventbox, formatAlaTeX(common::sprintf_fixutf8(translate($appletstate{$state_type}{tt}[0]), $battery)));
  my $menu = Gtk2::Menu->new;
  foreach (@$arr) {
    my $name = ref($actions{$_}{name}) eq 'CODE' ? $actions{$_}{name}->($battery) : $actions{$_}{name};
    my $launch = $actions{$_}{launch};
    if ($actions{$_}{choices}) {
      my $selected = $actions{$_}{choice_selected};
      $menu->append(gtkshow(create_menu($name, map {
	my $choice = $_;
	my $w = gtkshow(gtkset_active(Gtk2::CheckMenuItem->new_with_label($choice), $selected->($choice)));
	gtksignal_connect($w, activate => sub { $launch->($choice) });
	$w->set_draw_as_radio(1);
	$w;
      } $actions{$_}{choices}->())));
    } else {
      $menu->append(gtksignal_connect(gtkshow(Gtk2::MenuItem->new_with_label($name)), activate => sub { $launch->($battery) }));
    }
  }

  $menu->append(gtkshow(Gtk2::SeparatorMenuItem->new));
  $menu->append(gtksignal_connect(gtkshow(Gtk2::MenuItem->new_with_label(N("Get ACPI info"))), activate => sub { display_info() }));
  $menu->append(gtkshow(Gtk2::SeparatorMenuItem->new));
  $menu->append(gtksignal_connect(gtkset_active($checkmi = Gtk2::CheckMenuItem->new_with_label(N("Always launch on startup")), shouldStart()), toggled => sub { setAutoStart(uc(bool2text($checkmi->get_active))) }));
  $checkmi->show;
  $menu->append(gtksignal_connect(gtkshow(Gtk2::MenuItem->new_with_label(N("Quit"))), activate => sub { mainQuit() }));
  $menu
}

sub setAutoStart {
  my $state = shift;
  output_p $onstartupfile,
    qq(AUTOSTART=$state);
}

sub shouldStart() {
  my %p = getVarsFromSh($onstartupfile);
  my $ret = $p{AUTOSTART} eq 'FALSE' ? 0 : 1;
  $ret
}

sub is_running {
    my ($name) = @_;
    any {
      my ($ppid, $pid, $n) = /^\s*(\d+)\s+(\d+)\s+(.*)/;
      #- to run ps, perl may create some process with $name as name and 1 as ppid
      $ppid != 1 && $pid != $$ && $n eq $name;
    } `ps -o '%P %p %c' -u $ENV{USER}`;
}


gtkadd(my $icon = Gtk2::TrayIcon->new("Cpu_Applet"),
       gtkadd($eventbox = Gtk2::EventBox->new,
              gtkpack($img = Gtk2::Image->new)
             )
      );

$eventbox->signal_connect(button_press_event => sub {
			    if ($_[1]->button == 1) {
			      display_info
			    }
			    $_[1]->button == 3 && $menu and $menu->popup(undef, undef, undef, undef, $_[1]->button, $_[1]->time);
                          });


set_userspace;
my ($opt) = @ARGV;
if ($opt eq '--force' || $opt eq '-f') { setAutoStart('TRUE') };

shouldStart() or die "$onstartupfile should be set to TRUE or use cpu_applet --force";

# test value to get state applet
my $c = get_cpu_freq;
my $t = get_throttle;
if ($c eq $list_freq[0] || $t eq "100%") {
  go2State("minlife");
} elsif ($c eq $list_freq[-1] || $t eq "50%") {
  go2State("maxlife")
} elsif ($c eq $list_freq[3] || $t eq "5O%") {
  go2State("mediumlife")
} elsif ($c eq $list_freq[2] || $t eq "75%") {
  go2State("interlife")
} else { go2State("manuallife") }

$icon->show_all;
Gtk2->main;

ugtk2::exit(0);
