Gtk2 + Perl = fun!

Use some modules:

use Gtk2 '-init'; # basic
use Glib qw/ TRUE FALSE /; # makes for easier source reading
use Gnome2::Vte; # generic terminal widget, will come in useful

Then we create a new window:

my $window = Gtk2::Window->new;
$window->set_title('cpang');
$window->signal_connect( destroy => sub { Gtk2->main_quit } );
$window->set_border_width(5);

That set the title, a nicer border line and also, if someone closes this window, it will ask Gtk2 to close the application entirely. That comes in handy!

Now we'll create a vertical box and put it inside the window we created:

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

The first is a flag for homogeneous - I'm honestly not sure what it means. It has a spacing of 5.

Then we create a horizontal box and put it inside the previously created vertical box:

my $hbox = Gtk2::HBox->new( FALSE, 5 );
$vbox->pack_start( $hbox, TRUE, TRUE, 5 );

Now we'll start filling the horizontal box. Starting with a label:

my $label = Gtk2::Label->new('Module name:');
$hbox->pack_start( $label, FALSE, TRUE, 0 );

Now we're creating an entry (which is a textbox, basically). Also, sometimes people press "enter" on the textbox itself instead of on the button. So, if we were going to create a button (and we will), then we'll connect the textbox's "enter" event to the same event the button's click will have.

Of course, we want to pack it in the horizontal box, which will make it sit to the right of the label we created above.

my $entry = Gtk2::Entry->new;
$entry->signal_connect( activate => \&click );
$hbox->pack_start( $entry, TRUE, TRUE, 0 );

Now for the button we talked about:

my $button = Gtk2::Button->new('Install'); # button text
$button->signal_connect( clicked => \&click );
$hbox->pack_start( $button, FALSE, TRUE, 0 );

Now for some fun part. Let's add a terminal:

my $terminal = Gnome2::Vte::Terminal->new;
$vbox->pack_start( $terminal, TRUE, TRUE, 0 );

Now, the idea is that if someone clicks a button or presses "enter" on the text box, it will trigger an action, right? Makes sense. Of course, we don't want them to be able to continually send actions until that first command worked.

In order to avoid that, we're going to make the entry non-editable before we send the command. After the command in the terminal finishes, we want it to be editable again. Let's set up that last part:

$terminal->signal_connect( child_exited => sub { $entry->set_editable(1) } );

We're putting the "click" subroutine in the end to have all the variables (bad bad bad!) so let's finish the rest of the app:

$window->show_all; # showing the window
Gtk2->main; # starts Gtk2

Now we're free to write our "click" subroutine:

sub click {
my $text = $entry->get_text || '';
if ($text) {
# someone set a command, make the textbox now non-editable
$entry->set_editable(0);
# run the command inside the terminal:
$terminal->fork_command(
'cpanm', [ 'cpanm', $text ], undef, '/tmp', FALSE, FALSE, FALSE
);
}
}

So, yeah, it's not the cleanest of the code and definitely does not adhere to my insanely strict rules of clean code, but it's a nice start without a lot of effort. Here is an external link to a screenshot.

cpang start

I first started it to have a nicer GUI screen to install modules. I reckon that's what we miss. Sort of like how ppm has a nice GUI package manager - that doesn't really work well.

You can see the entire thing, pretty much the same code, here:
http://github.com/xsawyerx/cpang/blob/master/cpang.pl

If you feel like helping me write this, you're more than welcome. Fork it, patch it, fix it, hit it, etc. etc.

Leave a comment

About Sawyer X

user-pic Gots to do the bloggingz