#!/usr/bin/perl -w

# Ratbar: a nutritious breakfast snack for people on the move.
# Ratbar is a task bar for the Ratpoison window manager (http://ratpoison.sf.net/).
# The default output format for `ratpoison -c windows` is assumed.

# using Ratbar:
#  The leftmost button, with the triangle arrow, is the menu.
#  Right of the menu is the task bar.
#  The taskbar will list windows in the current group.
#  Clicking on a button in the task bar will select the corresponding window.
#  On the far right of Ratbar is the text display. This you don't technically use.
#  Ratbar can also receive commands from the file '~/.ratbar/command_queue'.
#  Valid commands are 'menu', which opens the ratbar menu, 'reparse', which re-reads
#  the menu file ~/.ratbar/menu and updates the menu listings, and 'quit', which
#  closes Ratbar (invalid commands are ignored).
#  All commands (valid or not) are removed from the queue upon execution.

# configuring Ratbar:
#  The menu is read from ~/.ratbar/menu
#  If this file doesn't exist, or is empty, there will be no menu.
#  The format for this file is label|command\n...
#  example menu file:
#   Mozilla|mozilla
#   reparse menu|echo reparse>>~/.ratbar/command_queue
#  The text display is the output from `~/.ratbar/text`
#  Further configuration can be made by editing this file.

use Gtk;

set_locale Gtk;
init Gtk;

# maximum length for a taskbar title
my $maxLength = 20;

my $window = new Gtk::Window("toplevel");
# outer box, holds everything
my $box = new Gtk::HBox(0,0);
# inner box, holds the task bar
my $box2 = new Gtk::HBox(0,0);
# GTK menus are kind of strange
my $menu = new Gtk::Menu();
my $menuBar = new Gtk::MenuBar();
my $menuButton = new Gtk::MenuItem();
my $arrow = new Gtk::Arrow("right","in");
# the text display
my $label = new Gtk::Label("");

# figure out the name ratbar will have in the taskbar
# so that it can be ignored
my @trash = split(/\//,$0);
my $progname;
foreach $string (@trash)
{
   $progname=$string;
}

$label->show();

# Configuration
parseMenu();
my $commandfile = $ENV{'HOME'}."/.ratbar/text";

# Cooperate with the delete signal
$window->signal_connect("delete_event", \&CloseAppWindow);

$menuButton->add($arrow);
$menuBar->append($menuButton);

$box->pack_start($menuBar,0,0,0);
$box->pack_end($label,0,0,0);

$window->border_width(0);
$window->add($box);
$window->show_all();

Gtk->timeout_add(500,\&idle);

main Gtk();
exit(0);

# ratbar's event loop
sub idle
{
   # get a command (if any are queued)
   $queueFile = $ENV{'HOME'}."/.ratbar/command_queue";
   if (open(QUEUE,$queueFile))
   {
      my @queue = <QUEUE>;
      close(QUEUE);
      if (@queue)
      {
         chomp $queue[0];
         if ($queue[0] ne "")
         {
            if ($queue[0] eq "reparse")
            {
               parseMenu();
            }
            elsif ($queue[0] eq "menu")
            {
               $menuButton->select();
            }
            elsif ($queue[0] eq "quit")
            {
               CloseAppWindow();
            }
         }
         @file = `sed -e 1d $queueFile`;
         open(QUEUE,">$queueFile");
         print QUEUE @file;
         close(QUEUE);
      }
   }

   # update text
   if (-e $commandfile && -x $commandfile)
   {
      my $text = `$commandfile`;
      chomp($text);
      $label->set_text(" ".$text." ");
   }

   #update taskbar
   $box2->destroy();
   $box2 = new Gtk::HBox(0,0);
   $windowString = `ratpoison -c windows`;
   @windows = split(/\n/,$windowString);
   foreach $window (@windows)
   {
      if (substr($window,2,length($window)-2) ne $progname)
      {
         $box2->pack_start(taskButton($window),0,0,0);
      }
   }
   $box2->show();
   $box->pack_start($box2,0,0,5);

   return 1;
}

# read ~/.ratbar/menu and repopulate ratbar's menu
sub parseMenu
{
   $menu->destroy();
   $menu = new Gtk::Menu();
   open(MENU,$ENV{'HOME'}."/.ratbar/menu") || return;
   my @lines=<MENU>;
   close(MENU);

   foreach $line (@lines)
   {
      chomp($line);
      ($title,$command) = split(/\|/,$line);
      $menu->append(menuItem($title,$command));
   }

   $menuButton->set_submenu($menu);
}

# create a menu item
sub menuItem
{
   my @args = @_;
   my $item = new Gtk::MenuItem($args[0]);
   $item->signal_connect("activate", sub { system($args[1]); });
   $item->show();
   return $item;
}

# create a button for the task bar
sub taskButton
{
   # truncate titles that are too long
   my ($window, @junk) = @_;
   if (length($window) > $maxLength)
   {
      $window = substr($window,0,$maxLength-3)."..."
   }
   # find the task number
   my $num;
   ($num, @trash) = split(/\*|\+|-/,$window);
   my $item = new Gtk::Button($window);
   $item->signal_connect("clicked", sub { system("ratpoison -c \"select $num\""); });
   $item->show();
   return $item;
}

sub CloseAppWindow
{
   Gtk->exit(0);
   return 0;
}
