# Copyright 2007 Kevin Ryde
# This file is part of Gtk2-Ex-OOP.
#
# Gtk2-Ex-OOP is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 3, or (at your option) any later
# version.
#
# Gtk2-Ex-OOP 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 General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see .
package Gtk2::Ex::GtkGCobj;
use strict;
use warnings;
use Carp;
our @ISA = ('Gtk2::Gdk::GC');
use constant DEBUG => 1;
sub get {
my $class = shift;
my $self = Gtk2::GC->get (@_);
$self->{'release_count'}++;
return bless $self, $class; # rebless
}
# DESTROY is called when the gc is no longer used from anywhere in perl.
# The dark magic in gtk2-perl will actually re-reference to keep it around
# if it's still in use by C code, so we have to cope with being "DESTROY"ed
# multiple times, hence the release count is decremented as well as actually
# doing them.
#
# If you're wondering whether this should be FINALIZE_INSTANCE per
# Glib::Object::Subclass, the answer is no, because that won't be called
# until after all "releases" make the pool let go of its reference on the
# gc, ie. you have to do the releases before you see FINALIZE_INSTANCE.
#
sub DESTROY {
my ($self) = @_;
if (DEBUG) { print "$self destroy, release count ",
($self->{'release_count'}||0), "\n"; }
while ($self->{'release_count'} > 0) {
$self->{'release_count'}--;
Gtk2::GC->release ($self);
}
$self->SUPER::DESTROY;
}
sub new ($%) {
my ($class, %values) = @_;
my $widget = delete $values{'widget'};
my $drawable = delete $values{'drawable'}
|| delete $values{'window'}
|| ($widget && $widget->window);
if (! $drawable) {
croak "Gtk2::Ex::GtkGCobj->new: no drawable specified";
}
my $colormap = delete $values{'colormap'}
|| ($widget && $widget->get_colormap)
|| $drawable->get_colormap;
my $depth = $drawable->get_depth;
my $values = \%values;
return $class->get ($depth, $colormap, $values);
}
1;
__END__
=head1 NAME
Gtk2::Ex::GtkGCobj -- auto-release for Gtk2::GC shared GCs
=head1 SYNOPSIS
use Gtk2::Ex::GtkGCobj;
# the plain "get" style
my $gc = Gtk2::Ex::GtkGCobj->get ($depth, $colormap, { attrs... });
# or friendlier attributes interface
my $gc = Gtk2::Ex::GtkGCobj->new (widget => $widget,
foreground => $color,
...);
=head1 OBJECT HIERARCHY
Glib::Object
Gtk2::Gdk::GC
Gtk2::Ex::GtkGCobj (Perl subclass only)
=head1 DESCRIPTION
C is a wrapper around the C pool of shared
graphics contexts adding an automatic C<< Gtk2::GC->release >> when the GC
is garbage collected by Perl.
Normally if you get a GC with C<< Gtk2::GC->get >> you have to remember to
C<< Gtk2::GC->release >> it when you're finished. If you just drop it then
the GC remains in the pool forever. It might be re-used later by chance,
but usually it's just a memory and X resource leak.
The GCs returned by C are a Perl subclass of
C and can be used everywhere an ordinary GC can be used --
the only difference is the auto-release.
As a bonus this module offers a C function with a friendlier interface
than C<< Gtk2::GC->get >>.
=head1 FUNCTIONS
=over 4
=item C<< Gtk2::Ex::GtkGCobj->get ($depth, $colormap, $values) >>
Return a shared GC with the given attributes. The arguments are the same as
for C<< Gtk2::GC->new >>, but the GC returned is the C
subclass and so is automatically released when garbage collected.
$gc = Gtk2::Ex::GtkGCobj->get ($my_depth, $my_colormap,
{ foreground => $my_color,
line_width => 10
});
=item C<< Gtk2::Ex::GtkGCobj->new (key => value, ...) >>
Return a shared GC with the given attributes. The key/value parameters are
the Perl wrapped C attributes such as C, and in
addition one or more of the following to give depth and colormap.
widget Gtk2::Widget
window Gtk2::Gdk::Window
drawable Gtk2::Gdk::Drawable
depth integer
colormap Gtk2::Gdk::Colormap
The simplest is to just pass a realized widget and let C
get the depth and colormap from that.
$gc = Gtk2::Ex::GtkGCobj->new (widget => $my_widget,
foreground => $my_color);
Or equally easily with a window,
$gc = Gtk2::Ex::GtkGCobj->new (window => $my_win,
foreground => $my_color);
Any drawable can be used, except that pixmaps might not have a colormap set.
If that's the case you can either set it with C<< $drawable->set_colormap >>
or pass a colormap explicitly and let the drawable just give the depth.
$gc = Gtk2::Ex::GtkGCobj->new (drawable => $my_pixmap,
colormap => $my_colormap,
foreground => $my_color);
Or finally depth and colormap can both be given explicitly, just as you
would for the C above, but in key/value style.
$gc = Gtk2::Ex::GtkGCobj->new (depth => 8,
colormap => $my_cmap,
foreground => $my_color);
=back
=head1 OTHER NOTES
The colormap parameter to C and to C here is so
C can be used through C<< $gc->set_rgb_fg_color >> and
friends. If you're not interested in that then it's pretty irritating to be
forced to give a colormap, because basic drawing operations don't need it
(only depth). Your pixel values will certainly be designed to look good in
some colormap on some intended final target window, but the GC doesn't need
to know when or where that will be, and in fact for a pseudocolor visual the
colormap doesn't even have to exist yet. If you know what you're doing it
probably works to pass any old colormap of the requisite depth, though be
sure to use the same one each time because the pool doesn't share GCs
between different colormaps.
As of Gtk version 2.12, C<< Gtk2::GtkGC->release >> will segfault if the GC
wasn't obtained from C<< Gtk2::GtkGC->get >>, or if more Cs than
Cs are done. Letting C keep track of the releasing
is thus a good thing (or if a segfault does occur then you'll know where to
start looking!).
=head1 SEE ALSO
L, L, L
=cut