#!/usr/bin/perl

# I tried to write this with Tk, as it uses less memory and is
# more widely available. Alas, Tk is rather broken with respect to embedding.

# on debian, do:
# apt-get install libgtk2-perl

# Also see the Gtk2::URxvt module family, which does this much cleaner
# and provides a real tabbed-terminal.

my $RXVT_BASENAME = "urxvt";
#my $RXVT_BASENAME = "urxvtc";

use Gtk2;
use Encode;

$SIG{CHLD} = 'IGNORE';

my $event_cb; # $wid => $cb

init Gtk2;

my $window = new Gtk2::Window 'toplevel';
$window->signal_connect (destroy => sub { exit(0) });


my $screen = $window->get_screen();

my $colormap = $screen->get_rgba_colormap();
if ($colormap) {
   print "Setting colormap\n";
   Gtk2::Widget->set_default_colormap($colormap);
}

Gtk2::Rc->parse_string(<<__);
style "my-button-style" {
   GtkWidget::focus-padding = 0
   GtkWidget::focus-line-width = 0
   xthickness = 0
   ythickness = 0
}

widget "*.my-close-button" style "my-button-style"
__

my $vbox = new Gtk2::VBox;
$window->add ($vbox);

my $notebook = new Gtk2::Notebook;
$vbox->pack_start ($notebook, 1, 1, 0);

$notebook->can_focus (0);
$notebook->set (scrollable => 1);

sub set_window_hints {
   my $window = shift;
   my $rxvt = shift;
   
   print "Setting window hints\n";
   
      my ($type, $format, @data)
         = $window->property_get (
              Gtk2::Gdk::Atom->intern ("WM_NORMAL_HINTS", 0),
              Gtk2::Gdk::Atom->intern ("WM_SIZE_HINTS", 0),
              0, 70*4, 0
           );
      my ($width_inc, $height_inc, $base_width, $base_height) = @data[9,10,15,16];
      print "Inc  = $width_inc x $height_inc\n";
      print "Base = $base_width x $base_height\n";

      my $hints = new Gtk2::Gdk::Geometry;
      $hints->base_width  ($base_width); $hints->base_height ($base_height);
      $hints->width_inc   ($width_inc);  $hints->height_inc  ($height_inc);

      $rxvt->get_toplevel->set_geometry_hints ($rxvt, $hints, [qw(base-size resize-inc)]);
}

sub new_terminal {
   print "New Terminal - $title [@args]\n";
   my ($title, @args) = @_;

   my ($notelabel, $label, $button) = mktablabel($title);

   my $rxvt = new Gtk2::Socket;
   $rxvt->can_focus (1);

   $rxvt->signal_connect_after (realize => sub {
      my $win = $_[0]->window;

      if (fork == 0) {
         print "Executing fork of $RXVT_BASENAME\n";
         exec $RXVT_BASENAME,
                 -embed => $win->get_xid, 
                 -depth => 32,
                 -bg => '[90]Black',
                 @args;
         exit (255);
      }

      0
   });

#   $rxvt->signal_connect_after (clicked => sub {
#      print "Clicked\n";
#   });
   
   $rxvt->signal_connect_after (plug_added => sub {
      print "Plug_added\n";
      my ($socket) = @_;
      my $plugged = ($socket->window->get_children)[0];

      $plugged->set_events ($plugged->get_events + ["property-change-mask"]);


      set_window_hints($plugged, $rxvt);
#      $wm_normal_hints->($plugged);

      $event_cb{$plugged} = sub {
         my ($event) = @_;
         my $window = $event->window;

         if (Gtk2::Gdk::Event::Configure:: eq ref $event) {
            set_window_hints($window, $rxvt);
#            $wm_normal_hints->($window);
         } elsif (Gtk2::Gdk::Event::Property:: eq ref $event) {
            my $atom = $event->atom;
            my $name = $atom->name;

            return if $event->state; # GDK_PROPERTY_NEW_VALUE == 0


            if ($name eq "_NET_WM_NAME") {
               my ($type, $format, $data)
                  = $window->property_get (
                       $atom,
                       Gtk2::Gdk::Atom->intern ("UTF8_STRING", 0),
                       0, 128, 0
                    );

               $label->set_text (Encode::decode_utf8 $data);
            }
         }

         0;
      };
      show_hide_tabs($notebook);

      0;
   });

   $rxvt->signal_connect_after (map_event => sub {
      print "map_event @_\n";
      $_[0]->grab_focus;
      0
   });

   $rxvt->signal_connect_after (unrealize => sub {
      print "unrealize @_\n";
      my $num_tabs = $notebook->get_n_pages();
      print "$num_tabs left\n";
      if ($num_tabs == 0) {
         exit(0);
      }
      show_hide_tabs($notebook);
      0;
   });



   $notebook->append_page ($rxvt, $notelabel);
   $notebook->set_tab_reorderable ($rxvt, 1);
   
   my $newpageno = $notebook->page_num ($rxvt);
   $button->set_data("page", $newpageno);

   $button->signal_connect_after("clicked", sub {
      my $b = $_[0];
      my $r = $_[1];
      my $pageno = $notebook->page_num($r);
      print "clicked: $pageno\n";
      $notebook->remove_page($pageno);
   }, $rxvt);


   $rxvt->show_all;

   $notebook->set_current_page ($newpageno);

   $rxvt;
}

sub show_hide_tabs {
   my $notebook = shift;
   my $pages = $notebook->get_n_pages();
   if ($pages == 1) {
      $notebook->set_show_tabs(0);
      $notebook->set_show_border(0);
      $notebook->can_focus(0);
   } else {
      $notebook->set_show_tabs(1);
      $notebook->can_focus(0);
   }
}

sub mktablabel {
   my $text = shift;
   
   my $l = new Gtk2::Label $text;
   #return ($l, $l, $l);
   
   my $b = new Gtk2::HBox;
   $b->pack_start($l, 1, 1, 0);
   
   my $button = Gtk2::Button->new();
   $button->set_relief('none');
   $button->set_focus_on_click(0);
   $button->set_name("my-close-button");
    
   my $close = Gtk2::Image->new_from_stock("gtk-close", "menu");
   
   $button->add($close);
   $b->pack_end($button, 1, 1, 0);

   foreach my $item ($b, $button, $l, $close) {
      $item->can_focus(0);
   }
   
   $b->show_all();
   
   return ($b, $l, $button);

}


#my $new = new Gtk2::Frame;
#$notebook->prepend_page ($new, "New");

$notebook->signal_connect_after (switch_page => sub {
   my $pages = $_[0]->get_n_pages();
   my $pno = $_[2] + 1;
   print "switch_page $pno/$pages\n";
   #if ($_[2] == 0) {
   #   if ($pages == 1) {
   #      exit(0);
   #   }
   #   new_terminal $RXVT_BASENAME;
   #}
});

new_terminal "Starting";
$window->set_default_size (700, 400);
$window->show_all;

# ugly, but gdk_window_filters are ot available in perl

Gtk2::Gdk::Event->handler_set (sub {
   my ($event) = @_;
   
   if (ref $event eq 'Gtk2::Gdk::Event::Key') {
      my $state = $event->state();
      #print "*********** Keypress *************\n";
      #print "State  : ".$state."\n";
      #print "Keyval : ".$event->keyval."\n";
      if ($state & ( GDK_SHIFT_MASK ) ) {
         if ($state & ( GDK_CONTROL_MASK )) {
            if ($event->type eq 'key-press') {
               if ($event->keyval == 84) {
                  new_terminal "Starting";
                  return;
               }
               if ($event->keyval == 87) {
                  print "Close tab\n";
                  $notebook->remove_page($notebook->get_current_page());
                  return;
               }
            }
         }
      }
      if ($state & ( GDK_MOD1_MASK )) {
         if ($event->type eq 'key-press') {
            if ($event->keyval >= 49 && $event->keyval < 59) {
               my $pageno = $event->keyval - 48;
               print "Setting Page $pageno\n";
               $notebook->set_current_page($pageno-1);
               return;
            }
         }
      }
         
      
      
   }
   #print "gtk event $event ".$event->type."\n";
   my $window = $event->window;

   ($event_cb{$window} && $event_cb{$window}->($event))
      or Gtk2->main_do_event ($event);
});

main Gtk2;

