#!/usr/bin/perl -w
#
# Images
#
# GtkImage is used to display an image; the image can be in a number of formats.
# Typically, you load an image into a GdkPixbuf, then display the pixbuf.
#
# This demo code shows some of the more obscure cases, in the simple
# case a call to gtk_image_new_from_file() is all you need.
#
# If you want to put image data in your program as a C variable,
# use the make-inline-pixbuf program that comes with GTK+.
# This way you won't need to depend on loading external files, your
# application binary can be self-contained.
#
package images;
use Glib qw(TRUE FALSE);
use Gtk2;
use strict;
my $i;
#include "demo-common.h"
my $window = undef;
my $pixbuf_loader = undef;
my $load_timeout = 0;
my $image_stream = undef;
sub error_popup {
my $parent = shift;
my $message = shift;
my $dialog = Gtk2::MessageDialog->new ($parent, 'destroy-with-parent',
'error', 'close', $message);
$dialog->signal_connect (response => sub {$_[0]->destroy; 1});
$dialog->show;
}
sub progressive_prepared_callback {
my ($loader, $image) = @_;
my $pixbuf = $loader->get_pixbuf;
#
# Avoid displaying random memory contents, since the pixbuf
# isn't filled in yet.
#
$pixbuf->fill (0xaaaaaaff);
$image->set_from_pixbuf ($pixbuf);
}
sub progressive_updated_callback {
my ($loader, $x, $y, $width, $height, $image) = @_;
#
# We know the pixbuf inside the GtkImage has changed, but the image
# itself doesn't know this; so queue a redraw. If we wanted to be
# really efficient, we could use a drawing area or something
# instead of a GtkImage, so we could control the exact position of
# the pixbuf on the display, then we could queue a draw for only
# the updated area of the image.
#
$image->queue_draw;
}
sub progressive_timeout {
my $image = shift;
#
# This shows off fully-paranoid error handling, so looks scary.
# You could factor out the error handling code into a nice separate
# function to make things nicer.
#
if (defined $image_stream) {
my $buf;
my $bytes_read = read ($image_stream, $buf, 512);
# sysread returns undef on error
if (not defined $bytes_read) {
error_popup ($window, "Failure reading image file 'alphatest.png': $!");
close $image_stream;
$image_stream = undef;
$load_timeout = 0;
return FALSE; # uninstall the timeout
}
if ($bytes_read == 0) {
warn "end of file";
close $image_stream;
$image_stream = undef;
return TRUE; # do NOT uninstall the timeout, we'll just start loading again
}
eval { $pixbuf_loader->write ($buf) };
if ($@) {
error_popup ($window, "Failed to load image: $@");
close $image_stream;
$image_stream = undef;
$load_timeout = 0;
return FALSE; # uninstall the timeout
}
if (eof $image_stream) {
close $image_stream;
$image_stream = undef;
#
# Errors can happen on close, e.g. if the image file was
# truncated we'll know on close that it was incomplete.
#
eval { $pixbuf_loader->close; };
if ($@) {
error_popup ($window, "Failed to load image: $@");
$pixbuf_loader = undef;
$load_timeout = 0;
return FALSE; # uninstall the timeout
}
$pixbuf_loader = undef;
}
} else {
my $error_message = undef;
#
# demo_find_file() looks in the the current directory first,
# so you can run gtk-demo without installing GTK, then looks
# in the location where the file is installed.
#
my $filename;
eval { $filename = main::demo_find_file ("alphatest.png"); };
if ($@) {
$error_message = $@;
} else {
open $image_stream, "<:raw", $filename
or $error_message = "Unable to open image file 'alphatest.png': $!";
}
if (not defined $image_stream) {
error_popup ($window, $error_message);
$load_timeout = 0;
return FALSE; # uninstall the timeout
}
if ($pixbuf_loader) {
$pixbuf_loader->close;
$pixbuf_loader = undef;
}
$pixbuf_loader = Gtk2::Gdk::PixbufLoader->new;
$pixbuf_loader->signal_connect (area_prepared =>
\&progressive_prepared_callback, $image);
$pixbuf_loader->signal_connect (area_updated =>
\&progressive_updated_callback, $image);
}
# leave timeout installed
return TRUE;
}
sub start_progressive_loading {
my $image = shift;
#
# This is obviously totally contrived (we slow down loading
# on purpose to show how incremental loading works).
# The real purpose of incremental loading is the case where
# you are reading data from a slow source such as the network.
# The timeout simply simulates a slow data source by inserting
# pauses in the reading process.
#
$load_timeout = Glib::Timeout->add (150, \&progressive_timeout, $image);
}
sub cleanup_callback {
my ($object, $data) = @_;
if ($load_timeout) {
Glib::Source->remove ($load_timeout);
$load_timeout = 0;
}
if ($pixbuf_loader) {
$pixbuf_loader->close;
$pixbuf_loader = undef;
}
if ($image_stream) {
close $image_stream;
}
$image_stream = undef;
}
sub toggle_sensitivity_callback {
my ($togglebutton, $container) = @_;
my $newstate = ! $togglebutton->get_active;
foreach my $child ($container->get_children) {
# don't disable our toggle
$child->set_sensitive ($newstate)
if $child != $togglebutton;
}
}
sub do {
if (!$window) {
$window = Gtk2::Window->new;
$window->set_title ("Images");
$window->signal_connect (destroy => sub { $window = undef; 1 });
$window->signal_connect (destroy => \&cleanup_callback);
$window->set_border_width (8);
my $vbox = Gtk2::VBox->new (FALSE, 8);
$vbox->set_border_width (8);
$window->add ($vbox);
my $label = Gtk2::Label->new;
$label->set_markup ("<u>Image loaded from a file</u>");
$vbox->pack_start ($label, FALSE, FALSE, 0);
my $frame = Gtk2::Frame->new;
$frame->set_shadow_type ('in');
#
# The alignment keeps the frame from growing when users resize
# the window
#
my $align = Gtk2::Alignment->new (0.5, 0.5, 0, 0);
$align->add ($frame);
$vbox->pack_start ($align, FALSE, FALSE, 0);
#
# demo_find_file() looks in the the current directory first,
# so you can run gtk-demo without installing GTK, then looks
# in the location where the file is installed.
#
my $pixbuf = undef;
eval {
$pixbuf = Gtk2::Gdk::Pixbuf->new_from_file
(main::demo_find_file ('gtk-logo-rgb.gif'));
};
if ($@) {
# This code shows off error handling. You can just use
# gtk_image_new_from_file() instead if you don't want to report
# errors to the user. If the file doesn't load when using
# gtk_image_new_from_file(), a "missing image" icon will
# be displayed instead.
#
error_popup ($window,
"Unable to open image file 'gtk-logo-rgb.gif': $@");
}
my $image = Gtk2::Image->new_from_pixbuf ($pixbuf);
$frame->add ($image);
# Animation
$label = Gtk2::Label->new;
$label->set_markup ("<u>Animation loaded from a file</u>");
$vbox->pack_start ($label, FALSE, FALSE, 0);
$frame = Gtk2::Frame->new;
$frame->set_shadow_type ('in');
#
# The alignment keeps the frame from growing when users resize
# the window
#
$align = Gtk2::Alignment->new (0.5, 0.5, 0, 0);
$align->add ($frame);
$vbox->pack_start ($align, FALSE, FALSE, 0);
my $filename;
eval {
$filename = main::demo_find_file ("floppybuddy.gif");
};
$image = Gtk2::Image->new_from_file ($filename);
$frame->add ($image);
# Progressive
$label = Gtk2::Label->new;
$label->set_markup ("<u>Progressive image loading</u>");
$vbox->pack_start ($label, FALSE, FALSE, 0);
$frame = Gtk2::Frame->new;
$frame->set_shadow_type ('in');
#
# The alignment keeps the frame from growing when users resize
# the window
#
$align = Gtk2::Alignment->new (0.5, 0.5, 0, 0);
$align->add ($frame);
$vbox->pack_start ($align, FALSE, FALSE, 0);
#
# Create an empty image for now; the progressive loader
# will create the pixbuf and fill it in.
#
$image = Gtk2::Image->new_from_pixbuf (undef);
$frame->add ($image);
start_progressive_loading ($image);
# Sensitivity control
my $button = Gtk2::ToggleButton->new ("_Insensitive");
$vbox->pack_start ($button, FALSE, FALSE, 0);
$button->signal_connect (toggled => \&toggle_sensitivity_callback, $vbox);
}
if (!$window->visible) {
$window->show_all;
} else {
$window->destroy;
$window = undef;
}
return $window;
}
1;
Gtk2->init;
&do;
$window->signal_connect (destroy => sub {Gtk2->main_quit; 1});
Gtk2->main;
1;
__END__
Copyright (C) 2003 by the gtk2-perl team (see the file AUTHORS for the
full list)
This library is free software; you can redistribute it and/or modify it under
the terms of the GNU Library General Public License as published by the Free
Software Foundation; either version 2.1 of the License, or (at your option) any
later version.
This library is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU Library General Public License for more
details.
You should have received a copy of the GNU Library General Public License along
with this library; if not, write to the Free Software Foundation, Inc., 59
Temple Place - Suite 330, Boston, MA 02111-1307 USA.