Someone was asking today how to display a chinese character web page using Tk, and I started toying around with Gtk2 and stumbled upon this old package from
muppet. I slightly modified it to use utf8 characters. I was so surprised by how well it displayed, that I'll post it here. It does a great job with http://perlmonks too. :-)
#!/usr/bin/perl -w
package MupZilla; # by muppet of Gtk2 fame, and perlmonks
# modified by zentara to show Chinese
use strict;
use Glib qw(TRUE FALSE);
use Gtk2;
use Gtk2::Html2;
use Gnome2::VFS;
use utf8;
use Encode;
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;
});
$cancel->set_sensitive (FALSE);
$view->signal_connect (on_url => sub {
my ($v, $url) = @_;
if ($url) {
$status->pop (1) if $status->{current};
$status->push (1, $self->mangle_uri ($url));
$status->{current} = $url;
} else {
$status->pop (1);
delete $status->{current};
}
});
$status->push (1, '');
# $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;
$self->{cancel} = $cancel;
}
sub vfs_fetch {
my %params = (chunk_size => 1024, @_);
#warn "vfs_fetch $params{uri}\n";
# FIXME this needs to be done with idles or io watches or
# Gnome2::VFS::Async or something
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}->($handle, $info);
do {
my ($tmp, $nread);
($result, $nread, $tmp) = $handle->read ($params{chunk_size});
$params{read_chunk}->($handle, $tmp);
} while ($result eq 'ok');
warn "calling finish";
$params{finish}->($handle);
$result = $handle->close;
# {
# my ($result, $handle) = Gnome2::VFS::Async->create
# ($params{uri}, # text uri
# 'read', # open mode
# TRUE, # exclusive
# 'user-read', # perm
# 0, # priority
# sub {
# warn "func @_\n",
# },
# []);
# }
}
use Data::Dumper;
sub mangle_uri {
my ($self, $uri) = @_;
# mangle it to be a full url. FIXME this is terrible.
return $uri if $uri =~ m{^\s*https?:};
if ($self->{base_uri}) {
$uri = $self->{base_uri}->get_scheme . "://"
. $self->{base_uri}->get_host_name
. ($uri =~ m{^/}
? ''
: $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 {
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 ($handle, $info) = @_;
$stream->set_mime_type ($info->get_mime_type);
$stream->set_cancel_func (sub {
warn "request_url cancelled\n";
$handle->close;
});
},
read_chunk => sub {
$stream->write ($_[1])
if length $_[1] > 0;
Gtk2->main_iteration
while Gtk2->events_pending;
},
finish => sub { warn "finish"; $stream->close; },
);
# silently ignore errors.
warn "# silently ignore errors. -- $result\n"
unless $result eq 'ok';
return FALSE;
});
}
sub link_clicked {
my ($document, $url, $mupzilla) = @_;
warn "link_clicked $url\n";
$mupzilla->load_uri ($mupzilla->mangle_uri ($url));
}
sub load_uri {
my ($self, $uri) = @_;
warn "load_uri $uri\n";
if (not $gnomevfsinitialized) {
Gnome2::VFS->init;
$gnomevfsinitialized = TRUE;
}
my $result = vfs_fetch (
uri => $uri,
prepared => sub {
my ($handle, $info) = @_;
$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";
$handle->close;
});
$self->{uri} = $uri;
$self->{base_uri} =
Gnome2::VFS::URI->new ($uri);
},
read_chunk => sub {
my $content = $_[1];
#this does the unicode character conversion
my $utf8 = decode('utf8',$content);
$self->{doc}->write_stream ($utf8)
if length $_[1];
# print "$_[1]\n";
Gtk2->main_iteration
while Gtk2->events_pending;
},
finish => sub {
warn "finish";
$self->{doc}->close_stream;
$self->{cancel}->set_sensitive (FALSE);
},
);
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);
$self->{cancel}->set_sensitive (TRUE);
}
}
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;});
# a demo page
$ARGV[0] ||= "http://en.wikipedia.org/wiki/Chinese_character";
$mupzilla->load_uri ($ARGV[0]) if @ARGV;
Gtk2->main;