Re: Drawing Area issues ( continued, with example )

2017-10-15 Thread Eric Cashon via gtk-perl-list

 
The Energy Monitor is looking good.

Eric

 


___
gtk-perl-list mailing list
gtk-perl-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-perl-list


Re: Drawing Area issues ( continued, with example )

2017-10-15 Thread Daniel Kasak
Thanks everyone. Once it was confirmed that we can't have multiple
cairo contexts happening, I slightly rewrote the graphing to just use
one, and it works fine. Screenshot:
http://tesla.duckdns.org/images/powercom.png

I'm getting close to another release of the above project ...

Dan

On Sun, Oct 15, 2017 at 1:16 PM,   wrote:
>
>
> Hi Dan,
>
> The graph axis can be made dynamic so that each graph is different. That way
> you can show different ranges side by side. I experimented a little with
> this by setting a couple of array values that hold the number of tick marks
> on each graph. It is in C. I think that I need a big screen for it. Then
> maybe I could test a large number of graphs and data points.
>
> Eric
>
> https://github.com/cecashon/OrderedSetVelociRaptor/blob/master/Misc/cairo_drawings/four_graphs2.c
>
___
gtk-perl-list mailing list
gtk-perl-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-perl-list


Re: Drawing Area issues ( continued, with example )

2017-10-14 Thread Eric Cashon via gtk-perl-list

 

 
Hi Dan,

The graph axis can be made dynamic so that each graph is different. That way 
you can show different ranges side by side. I experimented a little with this 
by setting a couple of array values that hold the number of tick marks on each 
graph. It is in C. I think that I need a big screen for it. Then maybe I could 
test a large number of graphs and data points.

Eric

https://github.com/cecashon/OrderedSetVelociRaptor/blob/master/Misc/cairo_drawings/four_graphs2.c


___
gtk-perl-list mailing list
gtk-perl-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-perl-list


Re: Drawing Area issues ( continued, with example )

2017-10-12 Thread Eric Cashon via gtk-perl-list

Hi Emmanuele,

Thank you for the answer here. Very helpful.

There is a code comment in gdkinternals.h that says

struct _GdkWindow
{
...
  struct {
/* The temporary surface that we're painting to. This will be composited
 * back into the window when we call end_paint. This is our poor-man's
 * way of doing double buffering. */
cairo_surface_t *surface;
...

This was how I was thinking about it. It is internal but the widgets GdkWindow 
surface is used. Right? Or is the only cairo surface being used to draw on is 
the top level GdkWindow surface by default?

By the way, Thanks for all the work you have done putting some of this stuff 
together. A lot more drawing potential in GTK these days.

Eric
___
gtk-perl-list mailing list
gtk-perl-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-perl-list


Re: Drawing Area issues ( continued, with example )

2017-10-12 Thread Emmanuele Bassi
On 11 October 2017 at 19:34, Eric Cashon via gtk-perl-list
 wrote:

I think there's some confusion, here, about the role of a GdkWindow
and rendering…

> This is something that I have had some trouble with at the app level. In
> GTK3, how drawing is done, has changed a bit between minor versions in GTK3.
> In order to get CSS, transparency, OpenGL and modern drawing techniques
> working well,,, things have changed. Here is an article about container
> windows. I have always considered containers not to have windows to draw on
> but that may not be true anymore.
>
> https://blog.gtk.org/2017/05/24/container-secrets/

Widgets do not need windows to draw any more. It hasn't been true for
years, even if the transition happened during the 3.x API series.

A GdkWindow itself doesn't mean that a real windowing system surface
is used to render its contents; this has been true since the 2.x days.

A GtkWidget has a GdkWindow for rendering *only* if
Gtk.Widget.set_has_window() is called with `TRUE`; additionally, a
GtkWidget can add more GdkWindows for separate rendering and input
handling, assuming it calls Gtk.Widget.register_window(), to let the
toolkit know.

Rendering starts from the top-level, and each widget will be
traversed, with the draw() virtual function being called with a Cairo
context. The nature of the Cairo context is entirely inconsequential,
so you should *never* assume anything about its state. You're only
supposed to draw your widget using the allocated size as the size of
the surface; if you want to make sure to avoid overdraw, in case
you're not using widgets but you're rendering your own objects, you
can also query the size of the clip, and avoid rendering things
outside of that region.

I wrote a blog post about how GTK+ renders last year, for the development blog:

  https://blog.gtk.org/2016/06/15/drawing-in-gtk/

> Some widgets might use the background window. For example a label or even a
> plug inside a socket. You can always try a GtkEventBox if you need a window
> to draw on behind a widget if it doesn't have it's own window.

You can also use Gtk.DrawingArea and call Gtk.Widget.set_has_window();
the drawing area widget will then create a GdkWindow for you inside
its realize() implementation.

> A GtkDrawingArea has it's own window to draw on.

No, it really doesn't.

Of course, unless you call Gtk.Widget.set_has_window(), which is not
the default. The default behaviour of GtkDrawingArea, in GTK+ 3.22, is
to use the parent's window. In a typical GTK application, this means
it'll render on the top-level window, which ideally should be the only
native windowing system surface in use for rendering.

Incidentally, for GTK+ 4.0 we're cleaning up this mess, and the only
windowing system surface for both rendering and input will be the one
created by GtkWindow; everything else will render on that, and input
will be handled by the GTK widget hierarchy.

> If you put a drawing area
> over the main window and draw on both with transparency you can see this.

This is not really correct.

Transparency is done via opacity groups in Cairo and GTK; if a widget
has a different opacity than its parent, and its parent also has a
different opacity than 1.0, it'll be rendered into an intermediate
surface, and then composited at the parent's opacity, to avoid
blending errors.

> How GTK draws the layout using cairo and the compositor might be a different
> argument though. Cairo contexts are the same.

Yes, the Cairo context is the same because the Cairo context is
propagated through the widget hierarchy, assuming that the surface
used as the target is the same. That's how we can implement
semi-transparent widgets, or how we can do things like border shadows
in CSS. This is also why it's fundamental to always draw using the
Cairo context given to you by GTK itself, and never call
gdk_cairo_create(). If you want to draw into an intermediate surface
you should create your own Cairo surface, render into it, and then use
that surface as the source on the Cairo context inside the draw()
implementation.

Ciao,
 Emmanuele.

-- 
https://www.bassi.io
[@] ebassi [@gmail.com]
___
gtk-perl-list mailing list
gtk-perl-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-perl-list


Re: Drawing Area issues ( continued, with example )

2017-10-12 Thread kaffeetisch
"Eric Cashon via gtk-perl-list" :
> A GtkDrawingArea has it's own window to draw on.

You're right, there seems to be a lot of changes going on in this area under 
the hood.  I was basing my statement on the C code in gtk+'s master branch, 
where drawing areas clearly have no GdkWindow of their own:

https://git.gnome.org/browse/gtk+/tree/gtk/gtkdrawingarea.c#n301

But it looks like this is a recent change, because on the gtk-3-22 branch 
drawing areas do have their own GdkWindow:

https://git.gnome.org/browse/gtk+/tree/gtk/gtkdrawingarea.c?h=gtk-3-22#n187
___
gtk-perl-list mailing list
gtk-perl-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-perl-list


Re: Drawing Area issues ( continued, with example )

2017-10-11 Thread Eric Cashon via gtk-perl-list

 

 
Hi Torsten,

This is something that I have had some trouble with at the app level. In GTK3, 
how drawing is done, has changed a bit between minor versions in GTK3. In order 
to get CSS, transparency, OpenGL and modern drawing techniques working well,,, 
things have changed. Here is an article about container windows. I have always 
considered containers not to have windows to draw on but that may not be true 
anymore.

https://blog.gtk.org/2017/05/24/container-secrets/

Some widgets might use the background window. For example a label or even a 
plug inside a socket. You can always try a GtkEventBox if you need a window to 
draw on behind a widget if it doesn't have it's own window.

A GtkDrawingArea has it's own window to draw on. If you put a drawing area over 
the main window and draw on both with transparency you can see this. How GTK 
draws the layout using cairo and the compositor might be a different argument 
though. Cairo contexts are the same.

The following has two transparent windows that you can draw on. Check out the 
context and gdkwindow pointer values.

Tested on Ubuntu 16.04 and GTK3.18. If you have GTK3.22 there will probably be 
a warning about is_composited() but it should still work. More changes.

Eric

#!/usr/bin/perl
use strict;
use diagnostics;
use warnings;
use Gtk3 '-init';
use Glib qw(TRUE FALSE);

my $window = Gtk3::Window->new();
$window->signal_connect('delete_event' => sub { Gtk3->main_quit; });
$window->set_default_size(400, 400);
$window->set_border_width(10);
$window->set_title("Layers");
$window->set_app_paintable(TRUE);
if ($window->is_composited())
  {
my $screen = $window->get_screen();  
my $visual=$screen->get_rgba_visual();
$window->set_visual($visual);
  }
else
  {
print "Couldn't set transparency.\n"
  }
$window->signal_connect('draw' => \&draw_window); 

my $da = Gtk3::DrawingArea->new();
$da->set_vexpand(TRUE);
$da->set_hexpand(TRUE);
$da->signal_connect('draw' => \&draw_da);

$window->add($da);

$window->show_all();
Gtk3->main;

sub draw_da 
{
  my ($widget, $cr, $data) = @_;
  print "da context " . $cr . "\n" . " da GdkWindow " . $widget->get_window() . 
"\n";
  my $width = $widget->get_allocated_width();
  my $height = $widget->get_allocated_height();
  
  #Drawing area tranparent background.
  $cr->set_source_rgba(0, 0, 0, 0);
  $cr->paint;

  #Draw a line.
  $cr->set_source_rgba(0, 1, 1, 0.5);
  $cr->set_line_width(40);
  
  $cr->move_to(0, $height / 2);
  $cr->line_to($width, $height / 2);
  $cr->stroke();
  
  return FALSE;
}
sub draw_window 
{
  my ($widget, $cr, $data) = @_;
  print "window context " . $cr . "\n" . " window GdkWindow " . 
$widget->get_window() . "\n";
  my $width = $widget->get_allocated_width();
  my $height = $widget->get_allocated_height();
  
  #Window semi-tranparent background.
  $cr->set_source_rgba(0, 0, 1, 0.6);
  $cr->paint;

  #Draw a line.
  $cr->set_source_rgba(1, 1, 0, 0.5);
  $cr->set_line_width(40);  
  $cr->move_to($width / 2, 0);
  $cr->line_to($width / 2, $height);
  $cr->stroke();
  
  return FALSE;
}



___
gtk-perl-list mailing list
gtk-perl-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-perl-list


Re: Drawing Area issues ( continued, with example )

2017-10-11 Thread Torsten Schönfeld
"Daniel Kasak" :
> Does anyone know ... would this bug be in the bindings, or in gtk+ or cairo?

If I understand correctly, this is by design.  GtkDrawingArea does not have its 
own GdkWindow, hence all GtkDrawingAreas within a GtkWindow share the 
underlying GdkWindow and thus the GdkDrawingContext and thus the cairo context. 
 Prior to invoking each draw callback, the shared cairo context is altered so 
that any drawing done with it ends up in the right spot.
___
gtk-perl-list mailing list
gtk-perl-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-perl-list


Re: Drawing Area issues ( continued, with example )

2017-10-10 Thread Daniel Kasak
Ah, thankyou :) Yes, indeed, if I avoid constructing further contexts,
it works. I can replace this with just calling set_source_rgba() on
the 1 context in *most* cases, though I'd have to have *two* passes
for the graphs, as I draw a 'highlight' line ( lighter colour ) as
well as the 'regular' line that encloses the bars ( and which I call
->fill inside of later ). Still, that's not much more work.

Does anyone know ... would this bug be in the bindings, or in gtk+ or cairo?

Dan

On Wed, Oct 11, 2017 at 1:43 PM, Jeremy Volkening  wrote:
> On Tue, Oct 10, 2017 at 09:38:03PM +1100, Daniel Kasak wrote:
>>
>> I've cut down my app to a "relatively small" example which doesn't
>> need a database connection or loads of other stuff. It's still 400+
>> lines ( with lots of whitespace ). I know it's asking a lot, but if
>> someone can figure out what I'm doing wrong, I'd be very grateful ...
>
>
> Your issues stem from the creation of multiple contexts referencing the
> DrawingArea surface within the 'draw' callback, i.e.
>
> my $surface = $cairo_context->get_target;
> # and later..
> my $this_stat_context = Cairo::Context->create( $surface );
>
> If you re-write your code without doing this -- just use the context passed
> into the 'draw' signal callback along with save() and restore() -- I think
> you will find your issues disappear. I haven't completely re-written your
> code, but I tested on one small bit and it had the desired effect.
>
> Why this happens is a little bit hazy to me. If you print the values
> passed into the 'draw' callback, you can see that all of the pointers to the
> cairo context are the same for the different DAs. Somehow this gets sorted
> out if you just use the context as given, but my guess is that when you are
> calling get_target() it returns the surface for the first DrawingArea only,
> and then your issues arise.
>
> Regards,
> Jeremy
>
> --
> Civilization is the limitless multiplication of unnecessary necessities.
> -- Mark Twain
> ___
> gtk-perl-list mailing list
> gtk-perl-list@gnome.org
> https://mail.gnome.org/mailman/listinfo/gtk-perl-list
___
gtk-perl-list mailing list
gtk-perl-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-perl-list


Re: Drawing Area issues ( continued, with example )

2017-10-10 Thread Jeremy Volkening

On Tue, Oct 10, 2017 at 09:38:03PM +1100, Daniel Kasak wrote:

I've cut down my app to a "relatively small" example which doesn't
need a database connection or loads of other stuff. It's still 400+
lines ( with lots of whitespace ). I know it's asking a lot, but if
someone can figure out what I'm doing wrong, I'd be very grateful ...


Your issues stem from the creation of multiple contexts referencing the
DrawingArea surface within the 'draw' callback, i.e.

my $surface = $cairo_context->get_target;
# and later..
my $this_stat_context = Cairo::Context->create( $surface );

If you re-write your code without doing this -- just use the context 
passed into the 'draw' signal callback along with save() and restore() 
-- I think you will find your issues disappear. I haven't completely 
re-written your code, but I tested on one small bit and it had the 
desired effect.


Why this happens is a little bit hazy to me. If you print the values
passed into the 'draw' callback, you can see that all of the pointers to 
the cairo context are the same for the different DAs. Somehow this gets 
sorted out if you just use the context as given, but my guess is that 
when you are calling get_target() it returns the surface for the first 
DrawingArea only, and then your issues arise.


Regards,
Jeremy

--
Civilization is the limitless multiplication of unnecessary necessities.
-- Mark Twain
___
gtk-perl-list mailing list
gtk-perl-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-perl-list


Re: Drawing Area issues ( continued, with example )

2017-10-10 Thread Daniel Kasak
Hi. Yes, I could do it that way, and I might have to if I can't figure
out what's wrong with the multi-drawing-area approach. It shouldn't be
required though, and there are complexities to using a single drawing
area - for example selecting dates that are quite disperse ( I'd have
to project each day's graph to have them all render side-side-side
without large gaps in between ).

Dan

On Wed, Oct 11, 2017 at 8:30 AM,   wrote:
>
> You might be able to just use one drawing area. Then you don't have to worry
> about creating and destroying drawing areas, surfaces and contexts. When you
> want to redraw, just "paint" the drawing area background and start drawing.
> This approach works well for most drawings.
>
> Test out the following and see if it is close. Just a grid in one or four
> panes with one drawing area.
>
> Eric
>
> #!/usr/bin/perl
> use strict;
> use diagnostics;
> use warnings;
> use Gtk3 '-init';
> use Glib qw(TRUE FALSE);
>
> my $window = Gtk3::Window->new();
> $window->signal_connect('delete_event' => sub { Gtk3->main_quit; });
> $window->set_default_size(800, 400);
> $window->set_border_width(10);
> $window->set_title("Graphs");
>
> #Number of graphs. Either 1 or 4. Changed by the two buttons.
> my $graphs = 1;
>
> my $da = Gtk3::DrawingArea->new();
> $da->set_vexpand(TRUE);
> $da->set_hexpand(TRUE);
> $da->signal_connect('draw' => \&draw_graph);
>
> my $single_button = Gtk3::Button->new( 'graph 1 date' );
> $single_button->signal_connect('clicked' => \&single_button_clicked, $da);
>
> my $multiple_button = Gtk3::Button->new( 'graph 4 dates' );
> $multiple_button->signal_connect('clicked' => \&multiple_button_clicked,
> $da);
>
> my $grid1 = Gtk3::Grid->new();
> $grid1->set_row_spacing(10);
> $grid1->attach($da, 0, 0, 4, 4);
> $grid1->attach($single_button, 1, 5, 1, 1);
> $grid1->attach($multiple_button, 2, 5, 1, 1);
>
> $window->add($grid1);
>
> $window->show_all();
> Gtk3->main;
>
> sub draw_graph
> {
>   my ($widget, $cr, $data) = @_;
>   my $width = $widget->get_allocated_width();
>   my $height = $widget->get_allocated_height();
>   #Some drawing variables.
>   my $x = 0;
>   my $y = 0;
>   my $graph_width = $width / $graphs;
>   my $vertical_width = $graph_width / 24;
>   my $horizontal_width = $height / 4;
>
>   #Paint background.
>   $cr->set_source_rgb(0, 0, 0);
>   $cr->paint;
>
>   #Vertical lines.
>   $cr->set_source_rgb(0, 0, 1);
>   $cr->set_line_width(1);
>   for (my $i=0; $i < $graphs; $i++)
> {
>   for (my $j = 0; $j < 24; $j++)
> {
>   $x = $i * $graph_width + $j * $vertical_width;
>   $cr->move_to($x, 0);
>   $cr->line_to($x, $height);
>   $cr->stroke();
> }
> }
>
>   #24 numbers.
>   $cr->set_source_rgb(1, 1, 1);
>   for (my $i=0; $i < $graphs; $i++)
> {
>   for (my $j = 0; $j < 24; $j++)
> {
>   $x = $i * $graph_width + $j * $vertical_width;
>   $cr->move_to($x + 5, $height - 10);
>   $cr->show_text ($j);
> }
> }
>
>   #Horizontal lines.
>   $cr->set_source_rgb(0, 0, 1);
>   for (my $i=0; $i < $graphs; $i++)
> {
>   for (my $j = 1; $j < 4; $j++)
> {
>   $y = $j * $horizontal_width;
>   $cr->move_to(0, $y);
>   $cr->line_to($width, $y);
>   $cr->stroke();
> }
> }
>
>   #4 numbers.
>   $cr->set_source_rgb(1, 1, 1);
>   for (my $i=0; $i < $graphs; $i++)
> {
>   for (my $j = 0; $j < 4; $j++)
> {
>   $y = $j * $horizontal_width;
>   $cr->move_to(5, $y + 20);
>   $cr->show_text (2000 - $j * 500);
> }
> }
>
>
>   #Draw graph blocks.
>   $cr->set_source_rgb(0, 1, 1);
>   $cr->set_line_width(10);
>   $cr->rectangle(0, 0, $width, $height);
>   $cr->stroke();
>   $cr->set_line_width(5);
>   for (my $i=1; $i < $graphs; $i++)
> {
>   $x = $i * $graph_width;
>   $cr->move_to($x, 0);
>   $cr->line_to($x, $height);
>   $cr->stroke();
> }
>
>   return FALSE;
> }
> sub single_button_clicked
> {
>   my ($widget, $da) = @_;
>   $graphs = 1;
>   $da->queue_draw();
> }
> sub multiple_button_clicked
> {
>   my ($widget, $da) = @_;
>   $graphs = 4;
>   $da->queue_draw();
> }
>
>
___
gtk-perl-list mailing list
gtk-perl-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-perl-list


Re: Drawing Area issues ( continued, with example )

2017-10-10 Thread Eric Cashon via gtk-perl-list

 
You might be able to just use one drawing area. Then you don't have to worry 
about creating and destroying drawing areas, surfaces and contexts. When you 
want to redraw, just "paint" the drawing area background and start drawing. 
This approach works well for most drawings. 

Test out the following and see if it is close. Just a grid in one or four panes 
with one drawing area.

Eric 

#!/usr/bin/perl
use strict;
use diagnostics;
use warnings;
use Gtk3 '-init';
use Glib qw(TRUE FALSE);

my $window = Gtk3::Window->new();
$window->signal_connect('delete_event' => sub { Gtk3->main_quit; });
$window->set_default_size(800, 400);
$window->set_border_width(10);
$window->set_title("Graphs");

#Number of graphs. Either 1 or 4. Changed by the two buttons. 
my $graphs = 1;

my $da = Gtk3::DrawingArea->new();
$da->set_vexpand(TRUE);
$da->set_hexpand(TRUE);
$da->signal_connect('draw' => \&draw_graph);

my $single_button = Gtk3::Button->new( 'graph 1 date' );
$single_button->signal_connect('clicked' => \&single_button_clicked, $da);

my $multiple_button = Gtk3::Button->new( 'graph 4 dates' );
$multiple_button->signal_connect('clicked' => \&multiple_button_clicked, $da);

my $grid1 = Gtk3::Grid->new();
$grid1->set_row_spacing(10);
$grid1->attach($da, 0, 0, 4, 4);
$grid1->attach($single_button, 1, 5, 1, 1);
$grid1->attach($multiple_button, 2, 5, 1, 1);

$window->add($grid1);

$window->show_all();
Gtk3->main;

sub draw_graph 
{
  my ($widget, $cr, $data) = @_;
  my $width = $widget->get_allocated_width();
  my $height = $widget->get_allocated_height();
  #Some drawing variables.
  my $x = 0;
  my $y = 0;
  my $graph_width = $width / $graphs;
  my $vertical_width = $graph_width / 24;
  my $horizontal_width = $height / 4;
  
  #Paint background.
  $cr->set_source_rgb(0, 0, 0);
  $cr->paint;

  #Vertical lines.
  $cr->set_source_rgb(0, 0, 1);
  $cr->set_line_width(1);
  for (my $i=0; $i < $graphs; $i++)
{
  for (my $j = 0; $j < 24; $j++)
{
  $x = $i * $graph_width + $j * $vertical_width;
  $cr->move_to($x, 0);
  $cr->line_to($x, $height);
  $cr->stroke();
}
}

  #24 numbers.
  $cr->set_source_rgb(1, 1, 1);
  for (my $i=0; $i < $graphs; $i++)
{
  for (my $j = 0; $j < 24; $j++)
{
  $x = $i * $graph_width + $j * $vertical_width;
  $cr->move_to($x + 5, $height - 10);
  $cr->show_text ($j);
}
}

  #Horizontal lines.
  $cr->set_source_rgb(0, 0, 1);
  for (my $i=0; $i < $graphs; $i++)
{
  for (my $j = 1; $j < 4; $j++)
{
  $y = $j * $horizontal_width;
  $cr->move_to(0, $y);
  $cr->line_to($width, $y);
  $cr->stroke();
}
}

  #4 numbers.
  $cr->set_source_rgb(1, 1, 1);
  for (my $i=0; $i < $graphs; $i++)
{
  for (my $j = 0; $j < 4; $j++)
{
  $y = $j * $horizontal_width;
  $cr->move_to(5, $y + 20);
  $cr->show_text (2000 - $j * 500);
}
}


  #Draw graph blocks.
  $cr->set_source_rgb(0, 1, 1);
  $cr->set_line_width(10);
  $cr->rectangle(0, 0, $width, $height);
  $cr->stroke();
  $cr->set_line_width(5);
  for (my $i=1; $i < $graphs; $i++)
{
  $x = $i * $graph_width;
  $cr->move_to($x, 0);
  $cr->line_to($x, $height);
  $cr->stroke();
}

  return FALSE;
}
sub single_button_clicked 
{
  my ($widget, $da) = @_; 
  $graphs = 1;
  $da->queue_draw();
}
sub multiple_button_clicked 
{
  my ($widget, $da) = @_; 
  $graphs = 4;
  $da->queue_draw(); 
}



___
gtk-perl-list mailing list
gtk-perl-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-perl-list