#!/usr/bin/perl -w package MupZilla; use strict; use Glib qw(TRUE FALSE); use Gtk2; use Gtk2::Html2; use Gnome2::VFS; my $gnomevfsinitialized = FALSE; use Glib::Object::Subclass Gtk2::Window::, signals => { }, properties => [ ], ; sub INIT_INSTANCE { my $self = shift; my $vbox = new Gtk2::VBox FALSE, 0; my $toolbar = new Gtk2::HBox FALSE, 6; my $back = new Gtk2::Button '_Back'; my $cancel = new Gtk2::Button '_Cancel'; my $label = new Gtk2::Label; my $address = new Gtk2::Entry; my $scroller = new Gtk2::ScrolledWindow; my $view = new Gtk2::Html2::View; my $status = new Gtk2::Statusbar; my $document = new Gtk2::Html2::Document; $document->signal_connect (request_url => \&request_url, $self); $document->signal_connect (link_clicked => \&link_clicked, $self); $view->set_document ($document); $label->set_markup_with_mnemonic ('_Address:'); $label->set_mnemonic_widget ($address); $address->signal_connect (activate => sub { my ($entry, $mupzilla) = @_; my $uri = $entry->get_text; if ($uri !~ m{^https?://}) { $uri = "http://".$uri; $entry->set_text ($uri); } $mupzilla->load_uri ($uri) if $uri; }, $self); $scroller->set_policy (qw(automatic automatic)); $cancel->signal_connect (clicked => sub { my $str = $document->current_stream; $str->cancel if $str; }); # $toolbar->pack_start ($back, FALSE, FALSE, 0); $toolbar->pack_start ($cancel, FALSE, FALSE, 0); $toolbar->pack_start ($label, FALSE, FALSE, 0); $toolbar->pack_start ($address, TRUE, TRUE, 0); $vbox->pack_start ($toolbar, FALSE, FALSE, 0); $scroller->add ($view); $vbox->pack_start ($scroller, TRUE, TRUE, 0); $vbox->pack_start ($status, FALSE, FALSE, 0); $self->add ($vbox); $vbox->show_all; $self->{address} = $address; $self->{doc} = $document; $self->{view} = $view; } sub vfs_fetch { my %params = (chunk_size => 1024, @_); warn "vfs_fetch $params{uri}\n"; my ($result, $handle) = Gnome2::VFS->open ($params{uri}, 'read'); return $result unless $result eq 'ok'; my (undef, $info) = $handle->get_file_info("default"); $params{prepared}->($info); do { my ($tmp, $nread); ($result, $nread, $tmp) = $handle->read ($params{chunk_size}); $params{read_chunk}->($tmp); } while ($result eq 'ok'); $params{finish}->(); $result = $handle->close; } use Data::Dumper; sub mangle_uri { my ($self, $uri) = @_; # mangle it to be a full url. FIXME this is terrible. warn "mangle_uri -- '$uri'\n"; if ($self->{base_uri}) { warn " base_uri -- '".$self->{base_uri}->get_scheme."'\n"; warn " -- '".$self->{base_uri}->get_host_name."'\n"; warn " -- '".$self->{base_uri}->extract_dirname."'\n"; $uri = $self->{base_uri}->get_scheme . "://" . $self->{base_uri}->get_host_name . $self->{base_uri}->extract_dirname . "/" . $uri; } else { $uri = $self->{uri}."/".$uri; } return $uri; } sub clear { my $self = shift; $self->{view}->set_document (undef); $self->{doc}->clear; $self->{view}->set_document ($self->{doc}); } sub request_url { warn Dumper(['request url', @_]); my ($document, $url, $stream, $mupzilla) = @_; # defer to idle for more responsive incremental page loading. Glib::Idle->add (sub { my $result = vfs_fetch ( uri => $mupzilla->mangle_uri ($url), prepared => sub { my $info = shift; $stream->set_mime_type ($info->get_mime_type); }, read_chunk => sub { $stream->write ($_[0]); Gtk2->main_iteration while Gtk2->events_pending; }, finish => sub { $stream->close; }, ); # silently ignore errors. warn "# silently ignore errors. -- $result\n"; return FALSE; }); } sub link_clicked { warn Dumper(['link_clicked', @_]); my ($document, $url, $mupzilla) = @_; $mupzilla->load_uri ($mupzilla->mangle_uri ($url)); } sub load_uri { warn Dumper(['load_uri', @_]); my ($self, $uri) = @_; if (not $gnomevfsinitialized) { Gnome2::VFS->init; $gnomevfsinitialized = TRUE; } my $result = vfs_fetch ( uri => $uri, prepared => sub { $self->clear; $self->{doc}->open_stream ("text/html"); $self->{doc}->current_stream ->set_cancel_func (sub { # XXX should close the VFS object here, too, # but we don't have a ref to it. warn "should cancel the vfs fetch"; }); $self->{uri} = $uri; $self->{base_uri} = Gnome2::VFS::URI->new ($uri); }, read_chunk => sub { $self->{doc}->write_stream ($_[0]) if length $_[0]; Gtk2->main_iteration while Gtk2->events_pending; }, finish => sub { $self->{doc}->close_stream; }, ); if ($result ne 'ok') { my $msg = Gtk2::MessageDialog->new ($self, [], 'error', 'ok', "Cannot open $uri: $result"); $msg->run; $msg->destroy; return; } else { $self->{address}->set_text ($uri); } } package main; use strict; use Gtk2 -init; my $mupzilla = new MupZilla; $mupzilla->set_default_size (600, 400); $mupzilla->show; $mupzilla->signal_connect (delete_event => sub {Gtk2->main_quit;}); Gtk2->main;