source: libcaca/trunk/ruby/caca-canvas.c @ 2821

Last change on this file since 2821 was 2821, checked in by Sam Hocevar, 11 years ago

Starting refactoring to get rid of libcucul. The initial reason for the
split is rendered moot by the plugin system: when enabled, binaries do
not link directly with libX11 or libGL. I hope this is a step towards
more consisteny and clarity.

  • Property svn:eol-style set to native
File size: 17.7 KB
Line 
1/*
2 *  libcaca Ruby bindings
3 *  Copyright (c) 2007 Pascal Terjan <pterjan@linuxfr.org>
4 *
5 *  This library is free software. It comes without any warranty, to
6 *  the extent permitted by applicable law. You can redistribute it
7 *  and/or modify it under the terms of the Do What The Fuck You Want
8 *  To Public License, Version 2, as published by Sam Hocevar. See
9 *  http://sam.zoy.org/wtfpl/COPYING for more details.
10 */
11
12#include <ruby.h>
13#include <caca.h>
14#include <errno.h>
15#include "caca-dither.h"
16#include "caca-font.h"
17#include "common.h"
18
19VALUE cCanvas;
20
21#define simple_func(x)                                  \
22static VALUE x (VALUE self)                             \
23{                                                       \
24    if( caca_##x (_SELF) <0)                           \
25        rb_raise(rb_eRuntimeError, strerror(errno));    \
26                                                        \
27    return self;                                        \
28}
29
30#define get_int(x)                                      \
31static VALUE get_##x (VALUE self)                       \
32{                                                       \
33    return INT2NUM(caca_get_##x (_SELF));              \
34}
35
36static void canvas_free(void * p)
37{
38    caca_free_canvas((caca_canvas_t *)p);
39}
40
41static VALUE canvas_alloc(VALUE klass)
42{
43    VALUE obj;   
44    obj = Data_Wrap_Struct(klass, NULL, canvas_free, NULL);
45    return obj;
46}
47
48VALUE canvas_create(caca_canvas_t *canvas)
49{
50    return Data_Wrap_Struct(cCanvas, NULL, NULL, canvas);
51}
52
53static VALUE canvas_initialize(VALUE self, VALUE width, VALUE height)
54{
55    caca_canvas_t *canvas;
56
57    canvas = caca_create_canvas(NUM2INT(width), NUM2INT(height));
58
59    if(canvas == NULL)
60    {
61        rb_raise(rb_eRuntimeError, strerror(errno));
62    }
63
64    _SELF = canvas;
65
66    return self;
67}
68
69get_int(canvas_height)
70get_int(canvas_width)
71
72static VALUE set_canvas_width(VALUE self, VALUE width)
73{
74    caca_set_canvas_size(_SELF, NUM2INT(width), caca_get_canvas_height(_SELF));
75    return width;
76}
77
78static VALUE set_canvas_width2(VALUE self, VALUE width)
79{
80    set_canvas_width(self, width);
81    return self;
82}
83
84static VALUE set_canvas_height(VALUE self, VALUE height)
85{
86    caca_set_canvas_size(_SELF, caca_get_canvas_width(_SELF), NUM2INT(height));
87    return height;
88}
89
90static VALUE set_canvas_height2(VALUE self, VALUE height)
91{
92    set_canvas_height(self, height);
93    return self;
94}
95
96static VALUE set_canvas_size(VALUE self, VALUE height, VALUE width)
97{
98    caca_set_canvas_size(_SELF, NUM2INT(width), NUM2INT(height));
99    return self;
100}
101
102/****/
103
104static VALUE gotoxy(VALUE self, VALUE x, VALUE y)
105{
106    if( caca_gotoxy(_SELF, NUM2INT(x), NUM2INT(y)) <0) {
107        rb_raise(rb_eRuntimeError, strerror(errno));
108    }
109    return self;
110}
111
112get_int(cursor_x)
113get_int(cursor_y)
114
115simple_func(clear_canvas)
116
117static VALUE put_char(VALUE self, VALUE x, VALUE y, VALUE ch)
118{
119    caca_put_char(_SELF, NUM2INT(x), NUM2INT(y), NUM2ULONG(ch));
120    return self;
121}
122
123static VALUE get_char(VALUE self, VALUE x, VALUE y)
124{
125    unsigned long int ch;
126    ch = caca_get_char(_SELF, NUM2INT(x), NUM2INT(y));
127    return INT2NUM(ch);
128}
129
130static VALUE put_str(VALUE self, VALUE x, VALUE y, VALUE str)
131{
132    caca_put_str(_SELF, NUM2INT(x), NUM2INT(y), StringValuePtr(str));
133    return self;
134}
135
136static VALUE get_attr(VALUE self, VALUE x, VALUE y)
137{
138    unsigned long int ch;
139    ch = caca_get_attr(_SELF, NUM2INT(x), NUM2INT(y));
140    return INT2NUM(ch);
141}
142
143static VALUE set_attr(VALUE self, VALUE attr)
144{
145    if(caca_set_attr(_SELF, NUM2ULONG(attr)) <0)
146        rb_raise(rb_eRuntimeError, strerror(errno));
147
148    return self;
149}
150
151static VALUE set_attr2(VALUE self, VALUE attr)
152{
153    set_attr(self, attr);
154    return self;
155}
156
157static VALUE put_attr(VALUE self, VALUE x, VALUE y, VALUE attr)
158{
159    if(caca_put_attr(_SELF, NUM2INT(x), NUM2INT(y), NUM2ULONG(attr)) <0)
160        rb_raise(rb_eRuntimeError, strerror(errno));
161
162    return self;
163}
164
165static VALUE set_color_ansi(VALUE self, VALUE fg, VALUE bg)
166{
167    if(caca_set_color_ansi(_SELF, NUM2INT(fg), NUM2INT(bg)) <0)
168        rb_raise(rb_eRuntimeError, strerror(errno));
169
170    return self;
171}
172
173static VALUE set_color_argb(VALUE self, VALUE fg, VALUE bg)
174{
175    if(caca_set_color_argb(_SELF, NUM2UINT(fg), NUM2UINT(bg)) <0) {
176        rb_raise(rb_eRuntimeError, strerror(errno));
177    }
178    return self;
179}
180
181static VALUE cprintf(int argc, VALUE* argv, VALUE self)
182{
183    int x, y;
184    VALUE rx, ry, format, rest, string;
185    rb_scan_args(argc, argv, "3*", &rx, &ry, &format, &rest);
186    x = NUM2INT(rx);
187    y = NUM2INT(ry);
188    string = rb_funcall2(rb_mKernel, rb_intern("sprintf"), argc-2, argv+2);
189    caca_put_str(_SELF, x, y, StringValuePtr(string));
190    return self;
191}
192
193
194get_int(canvas_handle_x)
195get_int(canvas_handle_y)
196
197static VALUE set_canvas_handle(VALUE self, VALUE x, VALUE y)
198{
199    caca_set_canvas_handle(_SELF, NUM2INT(x), NUM2INT(y));
200    return self;
201}
202
203static VALUE blit(int argc, VALUE* argv, VALUE self) {
204    VALUE x, y, src, mask;
205    caca_canvas_t *csrc, *cmask;
206
207    rb_scan_args(argc, argv, "31", &x, &y, &src, &mask);
208
209    Check_Type(x, T_FIXNUM);
210    Check_Type(y, T_FIXNUM);
211
212    if(CLASS_OF(src) != cCanvas)
213    {
214        rb_raise(rb_eArgError, "src is not a Cucul::Canvas");
215    }
216    Data_Get_Struct(src, caca_canvas_t, csrc);
217
218    if(!NIL_P(mask))
219    {
220        if(CLASS_OF(mask) != cCanvas)
221        {
222            rb_raise(rb_eArgError, "mask is not a Cucul::Canvas");
223        }
224        Data_Get_Struct(mask, caca_canvas_t, cmask);
225    }
226    else
227        cmask = NULL;
228   
229    if(caca_blit(_SELF, NUM2INT(x), NUM2INT(y), csrc, cmask)<0)
230        rb_raise(rb_eRuntimeError, strerror(errno));
231
232    return self;
233}
234
235static VALUE set_canvas_boundaries(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h)
236{
237    if(caca_set_canvas_boundaries(_SELF, NUM2INT(x), NUM2INT(y), NUM2UINT(w), NUM2UINT(h))<0)
238    {
239        rb_raise(rb_eRuntimeError, strerror(errno));
240    }
241    return self;
242}
243
244/****/
245
246simple_func(invert)
247simple_func(flip)
248simple_func(flop)
249simple_func(rotate_180)
250simple_func(rotate_left)
251simple_func(rotate_right)
252simple_func(stretch_left)
253simple_func(stretch_right)
254
255/****/
256
257static VALUE draw_line(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE ch)
258{
259    caca_draw_line(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2),NUM2ULONG(ch));
260    return self;
261}
262
263static VALUE draw_polyline(VALUE self, VALUE points, VALUE ch)
264{
265    int i, n;
266    int *ax, *ay;
267    int error = 0;
268    VALUE v, x, y;
269
270    n = RARRAY(points)->len;
271
272    ax = (int*)malloc(n*sizeof(int));
273    if(!ax)
274        rb_raise(rb_eNoMemError,"Out of memory");
275
276    ay = (int*)malloc(n*sizeof(int));
277    if(!ay)
278    {
279        free(ax);
280        rb_raise(rb_eNoMemError,"Out of memory");
281    }
282
283    for(i=0; i<n; i++)
284    {
285        v = rb_ary_entry(points, i);
286        if((TYPE(v) == T_ARRAY) && (RARRAY(v)->len == 2))
287        {
288            x = rb_ary_entry(v,0);
289            y = rb_ary_entry(v,1);
290            if(rb_obj_is_kind_of(x, rb_cInteger) &&
291               rb_obj_is_kind_of(y, rb_cInteger))
292            {
293                ax[i] = NUM2INT(x);
294                ay[i] = NUM2INT(y);
295            } else
296                error = 1;
297        }
298        else
299            error = 1;
300    }
301
302    if(error)
303    {
304        free(ax);
305        free(ay);
306        rb_raise(rb_eArgError, "Invalid list of points");
307    }
308
309    n--;
310
311    caca_draw_polyline(_SELF, ax, ay, n, NUM2ULONG(ch));
312
313    free(ax);
314    free(ay);
315
316    return self;
317}
318
319static VALUE draw_thin_line(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2)
320{
321    caca_draw_thin_line(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2));
322    return self;
323}
324
325static VALUE draw_thin_polyline(VALUE self, VALUE points)
326{
327    int i, n;
328    int *ax, *ay;
329    int error = 0;
330    VALUE v, x, y;
331
332    n = RARRAY(points)->len;
333
334    ax = (int*)malloc(n*sizeof(int));
335    if(!ax)
336        rb_raise(rb_eNoMemError,"Out of memory");
337
338    ay = (int*)malloc(n*sizeof(int));
339    if(!ay)
340    {
341        free(ax);
342        rb_raise(rb_eNoMemError,"Out of memory");
343    }
344
345    for(i=0; i<n; i++)
346    {
347        v = rb_ary_entry(points, i);
348        if((TYPE(v) == T_ARRAY) && (RARRAY(v)->len == 2))
349        {
350            x = rb_ary_entry(v,0);
351            y = rb_ary_entry(v,1);
352            if(rb_obj_is_kind_of(x, rb_cInteger) &&
353               rb_obj_is_kind_of(y, rb_cInteger))
354            {
355                ax[i] = NUM2INT(x);
356                ay[i] = NUM2INT(y);
357            } else
358                error = 1;
359        }
360        else
361            error = 1;
362    }
363
364    if(error)
365    {
366        free(ax);
367        free(ay);
368        rb_raise(rb_eArgError, "Invalid list of points");
369    }
370
371    n--;
372
373    caca_draw_thin_polyline(_SELF, ax, ay, n);
374
375    free(ax);
376    free(ay);
377
378    return self;
379}
380
381static VALUE draw_circle(VALUE self, VALUE x, VALUE y, VALUE r, VALUE ch)
382{
383    caca_draw_circle(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(r), NUM2ULONG(ch));
384    return self;
385}
386
387static VALUE draw_ellipse(VALUE self, VALUE x, VALUE y, VALUE a, VALUE b, VALUE ch)
388{
389    caca_draw_ellipse(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(a), NUM2INT(b), NUM2ULONG(ch));
390    return self;
391}
392
393static VALUE draw_thin_ellipse(VALUE self, VALUE x, VALUE y, VALUE a, VALUE b)
394{
395    caca_draw_thin_ellipse(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(a), NUM2INT(b));
396    return self;
397}
398
399static VALUE fill_ellipse(VALUE self, VALUE x, VALUE y, VALUE a, VALUE b, VALUE ch)
400{
401    caca_fill_ellipse(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(a), NUM2INT(b), NUM2ULONG(ch));
402    return self;
403}
404
405static VALUE draw_box(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h, VALUE ch)
406{
407    caca_draw_box(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h), NUM2ULONG(ch));
408    return self;
409}
410
411static VALUE draw_thin_box(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h)
412{
413    caca_draw_thin_box(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h));
414    return self;
415}
416
417static VALUE draw_cp437_box(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h)
418{
419    caca_draw_cp437_box(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h));
420    return self;
421}
422
423static VALUE fill_box(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h, VALUE ch)
424{
425    caca_fill_box(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h), NUM2ULONG(ch));
426    return self;
427}
428
429static VALUE draw_triangle(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE x3, VALUE y3, VALUE ch)
430{
431    caca_draw_triangle(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2),  NUM2INT(x3), NUM2INT(y3), NUM2ULONG(ch));
432    return self;
433}
434
435static VALUE draw_thin_triangle(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE x3, VALUE y3)
436{
437    caca_draw_thin_triangle(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2),  NUM2INT(x3), NUM2INT(y3));
438    return self;
439}
440
441static VALUE fill_triangle(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE x3, VALUE y3, VALUE ch)
442{
443    caca_fill_triangle(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2),  NUM2INT(x3), NUM2INT(y3), NUM2ULONG(ch));
444    return self;
445}
446
447static VALUE dither_bitmap(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h, VALUE d, VALUE pixels)
448{
449    if(CLASS_OF(d) != cDither)
450        rb_raise(rb_eArgError, "d is not a Cucul::Dither");
451    Check_Type(pixels, T_STRING);
452
453    caca_dither_bitmap(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h), DATA_PTR(d), StringValuePtr(pixels));
454    return self;
455}
456
457/****/
458
459get_int(frame_count)
460
461static VALUE set_frame(VALUE self, VALUE id)
462{
463    if(caca_set_frame(_SELF, NUM2INT(id))<0)
464        rb_raise(rb_eArgError, strerror(errno));
465
466    return self;
467}
468
469static VALUE set_frame2(VALUE self, VALUE id)
470{
471    set_frame(self, id);
472    return self;
473}
474
475static VALUE get_frame_name(VALUE self)
476{
477    return rb_str_new2(caca_get_frame_name(_SELF));
478}
479
480static VALUE set_frame_name(VALUE self, VALUE name)
481{
482    if(caca_set_frame_name(_SELF, StringValuePtr(name))<0)
483        rb_raise(rb_eRuntimeError, strerror(errno));
484
485    return self;
486}
487
488static VALUE set_frame_name2(VALUE self, VALUE name)
489{
490    set_frame_name(self, name);
491    return self;
492}
493
494static VALUE create_frame(VALUE self, VALUE id)
495{
496    if(caca_create_frame(_SELF, NUM2INT(id))<0) {
497        rb_raise(rb_eRuntimeError, strerror(errno));
498    }
499    return self;
500}
501
502static VALUE free_frame(VALUE self, VALUE id)
503{
504    if(caca_free_frame(_SELF, NUM2INT(id))<0) {
505        rb_raise(rb_eArgError, strerror(errno));
506    }
507    return self;
508}
509
510/****/
511
512static VALUE render_canvas(VALUE self, VALUE font, VALUE width, VALUE height, VALUE pitch)
513{
514    void *buf;
515    caca_font_t *f;
516    VALUE b;
517
518    if(CLASS_OF(font) != cFont)
519    {
520        rb_raise(rb_eArgError, "First argument is not a Cucul::Font");
521    }
522
523    buf = malloc(width*height*4);
524    if(buf == NULL)
525    {
526        rb_raise(rb_eNoMemError, "Out of memory");
527    }
528
529    f = DATA_PTR(font);
530    caca_render_canvas(_SELF, f, buf, NUM2UINT(width), NUM2UINT(height), NUM2UINT(pitch));
531
532    b = rb_str_new(buf, width*height*4);
533    free(buf);
534    return b;
535}
536
537static VALUE import_memory(VALUE self, VALUE data, VALUE format)
538{
539    long int bytes;
540    bytes = caca_import_memory (_SELF, StringValuePtr(data), RSTRING(StringValue(data))->len, StringValuePtr(format));
541    if(bytes <= 0)
542        rb_raise(rb_eRuntimeError, strerror(errno));
543
544    return self;
545}
546
547static VALUE import_file(VALUE self, VALUE filename, VALUE format)
548{
549    long int bytes;
550    bytes = caca_import_file (_SELF, StringValuePtr(filename), StringValuePtr(format));
551    if(bytes <= 0)
552        rb_raise(rb_eRuntimeError, strerror(errno));
553
554    return self;
555}
556
557static VALUE export_memory(VALUE self, VALUE format)
558{
559    unsigned long int bytes;
560    void *result;
561    VALUE ret;
562    result = caca_export_memory (_SELF, StringValuePtr(format), &bytes);
563    ret = rb_str_new(result, bytes);
564    free(result);
565    return ret;
566}
567
568get_singleton_double_list(export)
569get_singleton_double_list(import)
570
571/****/
572
573void Init_caca_canvas(VALUE mCucul)
574{
575    cCanvas = rb_define_class_under(mCucul, "Canvas", rb_cObject);
576    rb_define_alloc_func(cCanvas, canvas_alloc);
577
578    rb_define_method(cCanvas, "initialize", canvas_initialize, 2);
579    rb_define_method(cCanvas, "width", get_canvas_width, 0);
580    rb_define_method(cCanvas, "width=", set_canvas_width, 1);
581    rb_define_method(cCanvas, "set_width", set_canvas_width2, 1);
582    rb_define_method(cCanvas, "height", get_canvas_height, 0);
583    rb_define_method(cCanvas, "height=", set_canvas_height, 1);
584    rb_define_method(cCanvas, "set_height", set_canvas_height2, 1);
585    rb_define_method(cCanvas, "set_size", set_canvas_size, 2);
586       
587    rb_define_method(cCanvas, "gotoxy", gotoxy, 2);
588    rb_define_method(cCanvas, "cursor_x", get_cursor_x, 0);
589    rb_define_method(cCanvas, "cursor_y", get_cursor_y, 0);
590    rb_define_method(cCanvas, "handle_x", get_canvas_handle_x, 0);
591    rb_define_method(cCanvas, "handle_y", get_canvas_handle_y, 0);
592    rb_define_method(cCanvas, "set_handle", set_canvas_handle, 2);
593    rb_define_method(cCanvas, "blit", blit, -1);
594    rb_define_method(cCanvas, "set_boundaries", set_canvas_boundaries, 4);
595
596    rb_define_method(cCanvas, "clear", clear_canvas, 0);
597   
598    rb_define_method(cCanvas, "put_char", put_char, 3);
599    rb_define_method(cCanvas, "get_char", get_char, 2);
600    rb_define_method(cCanvas, "put_str", put_str, 3);
601    rb_define_method(cCanvas, "printf", cprintf, -1);
602
603    rb_define_method(cCanvas, "get_attr", get_attr, 3);
604    rb_define_method(cCanvas, "attr=", set_attr, 1);
605    rb_define_method(cCanvas, "set_attr", set_attr2, 1);
606    rb_define_method(cCanvas, "put_attr", put_attr, 3);
607    rb_define_method(cCanvas, "set_color_ansi", set_color_ansi, 2);
608    rb_define_method(cCanvas, "set_color_argb", set_color_argb, 2);
609
610    rb_define_method(cCanvas, "invert", invert, 0);
611    rb_define_method(cCanvas, "flip", flip, 0);
612    rb_define_method(cCanvas, "flop", flop, 0);
613    rb_define_method(cCanvas, "rotate_180", rotate_180, 0);
614    rb_define_method(cCanvas, "rotate_left", rotate_left, 0);
615    rb_define_method(cCanvas, "rotate_right", rotate_right, 0);
616    rb_define_method(cCanvas, "stretch_left", stretch_left, 0);
617    rb_define_method(cCanvas, "stretch_right", stretch_right, 0);
618
619    rb_define_method(cCanvas, "draw_line", draw_line, 5);
620    rb_define_method(cCanvas, "draw_polyline", draw_polyline, 2);
621    rb_define_method(cCanvas, "draw_thin_line", draw_thin_line, 4);
622    rb_define_method(cCanvas, "draw_thin_polyline", draw_thin_polyline, 1);
623    rb_define_method(cCanvas, "draw_circle", draw_circle, 4);
624    rb_define_method(cCanvas, "draw_ellipse", draw_ellipse, 5);
625    rb_define_method(cCanvas, "draw_thin_ellipse", draw_thin_ellipse, 4);
626    rb_define_method(cCanvas, "fill_ellipse", fill_ellipse, 5);
627    rb_define_method(cCanvas, "draw_box", draw_box, 5);
628    rb_define_method(cCanvas, "draw_thin_box", draw_thin_box, 4);
629    rb_define_method(cCanvas, "draw_cp437_box", draw_cp437_box, 4);
630    rb_define_method(cCanvas, "fill_box", fill_box, 5);
631    rb_define_method(cCanvas, "draw_triangle", draw_triangle, 7);
632    rb_define_method(cCanvas, "draw_thin_triangle", draw_thin_triangle, 6);
633    rb_define_method(cCanvas, "fill_triangle", fill_triangle, 7);
634    rb_define_method(cCanvas, "dither_bitmap", dither_bitmap, 6);
635
636    rb_define_method(cCanvas, "frame_count", get_frame_count, 0);
637    rb_define_method(cCanvas, "frame=", set_frame, 1);
638    rb_define_method(cCanvas, "set_frame", set_frame2, 1);
639    rb_define_method(cCanvas, "frame_name", get_frame_name, 0);
640    rb_define_method(cCanvas, "frame_name=", set_frame_name, 1);
641    rb_define_method(cCanvas, "set_frame_name", set_frame_name2, 1);
642    rb_define_method(cCanvas, "create_frame", create_frame, 1);
643    rb_define_method(cCanvas, "free_frame", free_frame, 1);
644
645    rb_define_method(cCanvas, "render", render_canvas, 4);
646    rb_define_method(cCanvas, "import_memory", import_memory, 2);
647    rb_define_method(cCanvas, "import_file", import_file, 2);
648    rb_define_method(cCanvas, "export_memory", export_memory, 1);
649    rb_define_singleton_method(cCanvas, "export_list", export_list, 0);
650    rb_define_singleton_method(cCanvas, "import_list", import_list, 0);
651   
652}
653
Note: See TracBrowser for help on using the repository browser.