--- ../irfc/irfc	Wed Aug  7 03:12:12 2002
+++ irfc	Wed Sep  4 19:24:22 2002
@@ -1,8 +1,8 @@
 #!/usr/bin/perl
 
-####################################################################################
-# Configuration                                                                    #
-####################################################################################
+###############################################################################
+# Configuration                                                               #
+###############################################################################
 
 # The directory structure to read (hint: use symlinks to build a structure
 # you like)
@@ -38,6 +38,7 @@
 %BUTTONS=( Down => "[down]",
            Up   => "[up]",
            Okay => "[enter]",
+           Back => "[back]",
            "+"  => "[fast_up]",
            "-"  => "[fast_down]",
            "1"  => "xmms /ftp/mp3z/music/playlist.m3u");
@@ -53,9 +54,13 @@
 $FONT='-*-*-*-r-*-*-*-180-*-*-*-*-*';
 #$FONT='-urw-bookman-demibold-r-normal-*-*-180-*-*-p-*-iso8859-2';
 
-####################################################################################
-# No changes below                                                                 #
-####################################################################################
+# Should we use polling? (uses 100% CPU)
+# Otherwise, use events: much nicer easier on the machine
+$USE_POLL=0;
+
+###############################################################################
+# No changes below                                                            #
+###############################################################################
 
 # apt-get install libgtk-perl
 use Gtk;
@@ -63,10 +68,12 @@
 # perl -MCPAN -e shell
 # install RCU
 use RCU;
+use RCU::Context;
+use RCU::Event;
 
-####################################################################################
-# License                                                                          #
-####################################################################################
+###############################################################################
+# License                                                                     #
+###############################################################################
 
 print STDERR <<end;
  /----------------------------------------------------------------\\
@@ -82,27 +89,43 @@
  \\----------------------------------------------------------------/
 end
 
-####################################################################################
-# Init                                                                             #
-####################################################################################
+# Changes by Kees Cook <kees@outflux.net>
+# - Event-based lirc (to not take 100% CPU)
+# - Added "Back" command to move up in the directory tree
+# - Small GTK clean-ups to reduce the size of unused space in the status window
+# - Cleaned up GTK clist
+# - Added file extension visibility
+
+# Forcibly disable the screen saver
+system("xset s off");
+
+###############################################################################
+# Init                                                                        #
+###############################################################################
 
 $false=0;
 $true=1;
 
 init Gtk;
+setupInput();  # Start listening for IR commands
 
-$_rcu = new RCU "RCU:Lirc";
-$_idle = Gtk->idle_add(\&idle);
+###############################################################################
+# Set up GUI                                                                  #
+###############################################################################
 
-####################################################################################
-# Set up GUI                                                                       #
-####################################################################################
+# Fontselection (Thanks to "Da Kourier" <dakourier@armitage.gotdns.com>)
+my $_style = new Gtk::Style;
+$_style->font( Gtk::Gdk::Font->load($FONT));
+
+# Info window size
+$INFO_SIZE = 110;	# FIXME: this should be set based on the font size
+$TIME_UPDATE=100;	# check the time every 1/10th of a second
 
 #Set up mainwindow
 $_mainwindow = new Gtk::Window( "toplevel" );
 $_mainwindow->set_title("IR File Chooser");
 $_mainwindow->set_position("center");
-#$_mainwindow->set_default_size($WINDOWSIZE[0],$WINDOWSIZE[1]);
+$_mainwindow->set_default_size($WINDOWSIZE[0],$WINDOWSIZE[1]);
 $_mainwindow->signal_connect("delete_event",\&CloseAppWindow);
 
 #Set up layoutmanager
@@ -113,24 +136,69 @@
 
 # This is the scrolled window to put the List widget inside
 $_scrollbox = new Gtk::ScrolledWindow( undef, undef );
-$_scrollbox->set_usize( $WINDOWSIZE[0], $WINDOWSIZE[1]-100 );
+#let the size come from other widgets
+#$_scrollbox->set_usize( $WINDOWSIZE[0], $WINDOWSIZE[1]-$INFO_SIZE );
+$_scrollbox->set_usize( -2, $WINDOWSIZE[1]-$INFO_SIZE );
+# auto scroll bars
+$_scrollbox->set_policy( 1, 1 );
 $_vbox->add( $_scrollbox );
 $_scrollbox->show();
 
-# The Info area
-$_infobox = new Gtk::Frame( "Info" );
-$_infobox->set_usize( $WINDOWSIZE[0], 100 );
-$_vbox->add( $_infobox );
-$_infobox->show();
-
-#Infolabel
-$_infolabel = new Gtk::Label("WELLCOME");
-$_infolabel->set_justify("left");
-$_infolabel->set_line_wrap($true);
-$_infobox->add( $_infolabel );
-$_infolabel->show();
-$_timer = Gtk->timeout_add(1000, \&displayDateTime);
+$USE_FRAME=1; # use a frame
+$USE_TEXT=0;  # don't use a text widget
+
+if ($USE_FRAME)
+{
+  # The Info area
+  $_infobox = new Gtk::Frame( );
+  $_infobox->border_width( 0 );
+  #let the size come from other widgets
+  #$_infobox->set_usize( $WINDOWSIZE[0], $INFO_SIZE );
+  $_vbox->add( $_infobox );
+  $_infobox->show();
+  #Infolabel
+  $_infolabel = new Gtk::Label("WELCOME");
+  $_infolabel->set_name( "welcome" );
+  $_infolabel->set_justify("center");
+  $_infolabel->set_line_wrap($false);
+  $_infobox->add( $_infolabel );
+  $_infolabel->show();
+}
+else
+{
+  if ($USE_TEXT)
+  {
+    $_infolabel = new Gtk::Text();
+    $_infolabel->set_editable($false);
+    $_infolabel->set_name( "welcome" );
+    $_infolabel->insert(undef,undef,undef,"WELCOME");
+  }
+  else
+  {
+    $_infolabel = new Gtk::Label("WELCOME");
+    $_infolabel->set_name( "welcome" );
+    $_infolabel->set_justify("left");
+    $_infolabel->set_line_wrap($true);
+  }
+  $_vbox->add( $_infolabel );
+  $_infolabel->show();
+}
+
+$_list = new Gtk::CList(2);
+$_list->set_style($_style);
+$_list->set_selection_mode("browse");
+$_list->column_titles_hide();
+#let the size come from other widgets
+#$_list->set_column_width(0,$WINDOWSIZE[0]-20);
+#$_list->set_column_width(1,0);
+$_list->set_column_visibility(1,$false);
+$_list->set_auto_sort($true);
+$_list->set_name( "dirlist" );
+$_list->signal_connect("key_press_event",\&ListOnKeyPress);
+$_scrollbox->add($_list);
+$_list->show();
 
+startTimeStatus();
 
 &buildList($MENUDIR);
 
@@ -145,23 +213,21 @@
 sub buildList($){
   my $path = $_[0];
   my ($file, $label, $ok, $ext);
-  # Fontselection (Thanks to "Da Kourier" <dakourier@armitage.gotdns.com>)
-  my $style = new Gtk::Style;
-     $style->font( Gtk::Gdk::Font->load($FONT));
-
-  if (defined($_list)){
-    $_list->destroy();
-  }
-  $_list = new Gtk::CList(3);
-  $_list->set_style($style);
-  $_list->set_selection_mode("browse");
-  $_list->column_titles_hide();
-  $_list->set_column_width(0,$WINDOWSIZE[0]-20);
-  $_list->set_column_width(1,0);
-  $_list->set_column_width(2,0);
-  $_list->set_auto_sort($true);
-  $_list->signal_connect("key_press_event",\&ListOnKeyPress);
 
+  $_list->freeze();
+  while ($_list->rows())
+  {
+    $_list->remove(0);
+  }
+  $_list->thaw();
+
+  # show screen being updated?  This doesn't seem to be working...
+  #Gtk->main_iteration() while (Gtk->events_pending());
+  #while (Gtk->events_pending()) { Gtk->main_iteration(); }
+  Gtk::Gdk->flush();
+  #while (Gtk->main_iteration_do($false)) { ; }
+
+  $_list->freeze();
   opendir(ROOT, $path);
   my @files = readdir(ROOT);
   closedir(ROOT);
@@ -181,6 +247,7 @@
       }elsif (defined($ext)){
         $label = $file;
         $label =~ s/\.$ext$//i;
+	$label = "$label ($ext)";
       }else{
         next;
       }
@@ -189,10 +256,9 @@
     $_list->append($label, $fullFilename);
   }
 
-  $_list->show();
-  $_scrollbox->add($_list);
-  $_list->grab_focus();
   $_list->select_row(0,0);  
+  $_list->thaw();
+  $_list->grab_focus();
 }
 
 sub CloseAppWindow{
@@ -209,11 +275,95 @@
   }
 }
 
+# Go up one directory
+sub onBack(){
+  my $file = $_list->get_text(0,1);
+
+  $file = substr($file, 0, rindex($file,'/'));
+
+  # don't go up past top
+  return if ($file eq $MENUDIR);
+
+  $file = substr($file, 0, rindex($file,'/'));
+  &buildList($file);
+}
+
+sub stopTimeStatus(){
+  # pause timer
+  Gtk->timeout_remove($_timer);
+}
+
+sub startTimeStatus(){
+  # put timer back
+  displayDateTime();
+  $_timer = Gtk->timeout_add($TIME_UPDATE, \&displayDateTime);
+}
+
+sub setupInput(){
+  if ($USE_POLL==1) {
+    $_rcu = new RCU "RCU:Lirc:irfc";
+  }
+  else {
+    $_rcu_context = new RCU::Context;
+    $_rcu_context->bind("=.*",
+	  sub {
+		  my ($history,$time,$rcu)=@_;
+		  $history=~/=(.*)/;
+		  my $key=$1;
+		  gotEvent($key);
+	  }
+    );
+    $_rcu_ignore_context = new RCU::Context;
+    $_rcu_ignore_context->bind("=.*",
+	  sub {
+		  my ($history,$time,$rcu)=@_;
+		  $history=~/=(.*)/;
+		  my $key=$1;
+	  }
+    );
+    $_rcu_event = new RCU::Event "RCU:Lirc:irfc";
+    $_rcu_event->set_context($_rcu_context);
+  }
+  $_idle = Gtk->idle_add(\&idle);
+}
+
+sub ignoreInput(){
+  # stop listening for commands
+  if ($USE_POLL==1) {
+    Gtk->idle_remove($_idle);
+  }
+  else {
+    $_rcu_event->set_context($_rcu_ignore_context);
+  }
+
+}
+
+sub takeInput(){
+  # listen for commands
+  if ($USE_POLL==1) {
+    $_idle = Gtk->idle_add(\&idle);
+  }
+  else {
+    # flush any pending RCU events
+    while ( Event::one_event(0.1) == 1)
+    {
+	# print "skipping event\n";
+    }
+    # start listening again
+    $_rcu_event->set_context($_rcu_context);
+  }
+
+}
+
 sub onEnter(){
   my $index = $_list->selection();
-  print $index;
   my $file = $_list->get_text($index,1);
 
+  stopTimeStatus();
+  ignoreInput();
+
+  # this doesn't work for some reason
+  updateStatus("- WAIT -");
 
   if (-d $file){
     #check if it is a mountpoint:
@@ -239,23 +389,46 @@
     }
     &execute($command);
   }
+
+  takeInput();
+  startTimeStatus();
 }
 
 sub execute($){
   my $command = $_[0];
-  Gtk->timeout_remove($_timer);
-  Gtk->idle_remove($_idle);
   $_mainwindow->hide();
   Gtk->main_iteration() while (Gtk->events_pending());
   system($command);
   $_mainwindow->show();
-  $_idle = Gtk->idle_add(\&idle);
-  $_timer = Gtk->timeout_add(1000, \&displayDateTime);
+}
+
+# Update the status window only on a change
+$PREV_STATUS="";
+sub updateStatus{
+  my ($status)=@_;
+  if ($PREV_STATUS ne $status)
+  {
+    if ($USE_TEXT)
+    {
+      $_infolabel->freeze();
+      $_infolabel->set_point(0);
+      $_infolabel->forward_delete($_infolabel->get_length());
+      $_infolabel->insert(undef,undef,undef,$status);
+      $_infolabel->thaw();
+    }
+    else
+    {
+      $_infolabel->set_text($status);
+    }
+    $PREV_STATUS=$status;
+  }
 }
 
 sub displayDateTime{
-  my $t = localtime(time());
-  $_infolabel->set_text($t);
+  my $t;
+  chomp($t = localtime(time()));
+  updateStatus($t);
+  
   return $true;
 }
 
@@ -289,8 +462,8 @@
   }
 }
 
-sub idle{
-  my ($key, $repeat) = $_rcu->poll;
+sub gotEvent{
+  my ($key,$repeat) = @_;
   my $cmd = $BUTTONS{$key} if (defined($key));
   if ( defined($cmd) and !($repeat % $DROPREPEATS) ){
     #check buttons
@@ -302,12 +475,30 @@
       &moveinlist(-5);
     }elsif ($cmd eq "[fast_down]"){
       &moveinlist(+5);
+    }elsif ($cmd eq "[back]"){
+      &onBack();
     }elsif ($cmd eq "[enter]"){
       &onEnter();
     }else{
+      stopTimeStatus();
+      ignoreInput();
       #execute quicklink
       &execute($cmd);
+      takeInput();
+      startTimeStatus();
     }
   }
   return $true;
 }
+  
+sub idle{
+  if ($USE_POLL==1) {
+    my ($key, $repeat) = $_rcu->poll;
+    return gotEvent($key,$repeat);
+  }
+  else {
+    # grab any pending keypresses
+    Event::one_event(0.2);
+    return $true;
+  }
+}
