The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde

# This file is part of Math-Image.
#
# Math-Image 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.
#
# Math-Image 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 Math-Image.  If not, see <http://www.gnu.org/licenses/>.


package App::MathImage::Gtk2::Generator;
use 5.008;
use strict;
use warnings;
use Carp;
use Scalar::Util;
use Glib 1.220; # for SOURCE_REMOVE
use Glib::Ex::SourceIds;

use Image::Base::Gtk2::Gdk::Pixmap;
use base 'App::MathImage::Generator';

# uncomment this to run the ### lines
#use Devel::Comments '###';


our $VERSION = 110;

use constant _DEFAULT_IDLE_TIME_SLICE => 0.25;  # seconds
use constant _DEFAULT_IDLE_TIME_FIGURES => 1000;  # drawing requests
use constant _PRIORITY => Glib::G_PRIORITY_LOW();  # below redraw

### *DESTROY = sub { print "Gtk2-Generator DESTROY\n" }

sub new {
  my $class = shift;
  ### Gtk2-Generator new()...

  my $self = $class->SUPER::new (step_time    => _DEFAULT_IDLE_TIME_SLICE,
                                 step_figures => _DEFAULT_IDLE_TIME_FIGURES,
                                 idle_ids     => Glib::Ex::SourceIds->new,
                                 use_class_negative => 1,
                                 @_);
  if ($self->{'gtkmain'}) { Scalar::Util::weaken ($self->{'gtkmain'}); }
  if ($self->{'widget'})  { Scalar::Util::weaken ($self->{'widget'}); }
  # if ($self->{'window'})  { Scalar::Util::weaken ($self->{'window'}); }

  # print "new \"widget\" $self->{'widget'} isweak ",
  #   Scalar::Util::isweak($self->{'widget'}),"\n";

  ### widget: "$self->{'widget'}"
  # either Drawing widget window or rootwin
  my $window = $self->{'window'}
    || $self->{'widget'}->window
      || do {
        ### no window ...
        return $self; # croak 'Gtk2-Generator no window specified';
      };
  ### window: "$window"
  my ($width, $height) = $window->get_size;

  my $image = Image::Base::Gtk2::Gdk::Pixmap->new
    (-for_drawable => $window,
     -width        => $width,
     -height       => $height);
  $self->{'pixmap'} = $image->get('-pixmap');

  if ($self->{'draw_progressive'}) {
    require Image::Base::Gtk2::Gdk::Window;
    my $image_window = Image::Base::Gtk2::Gdk::Window->new
      (-window => $window);

    require Image::Base::Multiplex;
    $image = Image::Base::Multiplex->new
      (-images => [ $image, $image_window ]);
  }
  $self->{'image'} = $image;

  if (! eval { $self->draw_Image_start ($image); 1 }) {
    my $err = $@;
    ### $err;
    my ($main, $statusbar);
    if (($main = $self->{'gtkmain'})
        && ($statusbar = $main->get('statusbar'))) {
      require Gtk2::Ex::Statusbar::MessageUntilKey;
      $err =~ s/\n+$//;
      Gtk2::Ex::Statusbar::MessageUntilKey->message($statusbar, $err);
    }

    undef $self->{'path_object'};
    undef $self->{'affine_object'};
    App::MathImage::Gtk2::Drawing::draw_text_centred
        ($self->{'widget'}, $self->{'pixmap'}, $err);
    _drawing_finished ($self);
    return $self;
  }

  Scalar::Util::weaken (my $weak_self = $self);
  _sync_handler (\$weak_self);
  return $self;
}

sub _sync_handler {
  my ($ref_weak_self) = @_;
  ### Gtk2-Generator _sync_handler()...
  my $self = $$ref_weak_self || return;

  $self->{'sync_pending'} = 0;
  ### add idle: $self->{'idle_ids'}
  $self->{'idle_ids'}->remove;
  $self->{'idle_ids'}->add (Glib::Idle->add (\&_idle_handler_draw,
                                             $ref_weak_self,
                                             _PRIORITY));
}

sub _idle_handler_draw {
  my ($ref_weak_self) = @_;
  ### Gtk2-Generator _idle_handler_draw()...

  if (my $self = $$ref_weak_self) {
    $self->{'idle_ids'}->remove;
    if ($self->draw_Image_steps ()) {
      ### keep drawing...
      unless ($self->{'sync_pending'}) {
        ### start sync...
        Gtk2::Ex::SyncCall->sync ($self->{'widget'},
                                  \&_sync_handler, $ref_weak_self);
        $self->{'sync_pending'} = 1;
      }
    } else {
      ### done, install pixmap...
      _drawing_finished ($self);
    }
  }
  ### _idle_handler_draw() end...
  return Glib::SOURCE_REMOVE;
}

sub _drawing_finished {
  my ($self) = @_;
  ### Gtk2-Generator _drawing_finished()...

  my $pixmap = $self->{'pixmap'};
  my $window = $self->{'window'};
  ### set_back_pixmap: "$pixmap"
  $window->set_back_pixmap ($pixmap);
  $window->clear;

  if (my $wc = $self->{'widgetcursor'}) {
    $wc->active(0);
    # Scalar::Util::weaken($wc);
    # ### $wc
  }

  # if ($drawing->{'window'} == $self->window) {
  #   $self->queue_draw;
  # } else {
  #   $window->clear;  # for root window
  # }
}

sub draw {
  my $class = shift;
  my $self = $class->new (@_,
                          draw_progressive => 0);
  while ($self->draw_steps) {
    ### Generator-X11 more...
  }
  _drawing_finished ($self);
}

1;
__END__