[cairo-commit] rcairo/src cairo.c,NONE,1.1 extconf.rb,NONE,1.1 image.c,NONE,1.1 shared.h,NONE,1.1 xlib.c,NONE,1.1

Evan Martin commit at pdx.freedesktop.org
Tue Oct 28 10:27:24 PST 2003


Committed by: martine

Update of /cvs/cairo/rcairo/src
In directory pdx:/tmp/cvs-serv31046/src

Added Files:
	cairo.c extconf.rb image.c shared.h xlib.c 
Log Message:
Initial import of Ruby/Cairo.

I just moved the code around a bit in anticipation of wanting to do it later,
and I haven't tested if it broke anything yet, so don't be surprised if it
doesn't quite build yet.


--- NEW FILE: cairo.c ---
/* ruby-cairo - Ruby bindings for Cairo.
 * Copyright (C) 2003 Evan Martin <martine at danga.com>
 *
 * vim: tabstop=4 shiftwidth=4 noexpandtab :
 */

#include "shared.h"

VALUE mCairo, cCairo, cCairoSurface, cCairoMatrix;

cairo_t*
rcairo_get_cairo(VALUE vcairo) {
	cairo_t *cr;
	Data_Get_Struct(vcairo, cairo_t, cr);
	return cr;
}
VALUE
rcairo_new() {
	cairo_t *cr = cairo_create();
	cairo_reference(cr);
	return Data_Wrap_Struct(cCairo, NULL, cairo_destroy, cr);
}
static VALUE
rcairo_rcairo_new(VALUE class) {
	return rcairo_new();
}

static VALUE
rcairo_dup(VALUE vself) {
	VALUE vdest = rcairo_new();
	cairo_copy(rcairo_get_cairo(vdest), rcairo_get_cairo(vself));
	rb_iv_set(vdest, "@target_image", rb_iv_get(vself, "@target_image"));
	return vdest;
}

static VALUE
rcairo_set_target_image(VALUE vself, VALUE vimage) {
	RCairoImage *img;

	img = rcairo_image_get_image(vimage);
	rb_iv_set(vself, "@target_image", vimage);
	cairo_set_target_image(rcairo_get_cairo(vself), img->data, img->format,
	                       img->width, img->height, img->stride);
	return Qnil;
}

static VALUE
rcairo_set_dash(VALUE vself, VALUE vdashes, VALUE offset) {
	rb_notimplement();
	return Qnil;
}

static VALUE
rcairo_run_pt_func(VALUE vself, VALUE pt, void (*f)(cairo_t*,double*,double*)) {
	double x = NUM2DBL(rb_ary_entry(pt, 0));
	double y = NUM2DBL(rb_ary_entry(pt, 1));
	f(rcairo_get_cairo(vself), &x, &y);
	return rb_ary_new3(2, rb_float_new(x), rb_float_new(y));
}
static VALUE
rcairo_transform_point(VALUE vself, VALUE pt) {
	return rcairo_run_pt_func(vself, pt, cairo_transform_point);
}
static VALUE
rcairo_transform_distance(VALUE vself, VALUE pt) {
	return rcairo_run_pt_func(vself, pt, cairo_transform_distance);
}
static VALUE
rcairo_inverse_transform_point(VALUE vself, VALUE pt) {
	return rcairo_run_pt_func(vself, pt, cairo_inverse_transform_point);
}
static VALUE
rcairo_inverse_transform_distance(VALUE vself, VALUE pt) {
	return rcairo_run_pt_func(vself, pt, cairo_inverse_transform_distance);
}

static VALUE
rcairo_text_extents(VALUE vself, VALUE text) {
	double x, y, w, h, dx, dy;
	cairo_text_extents(rcairo_get_cairo(vself), STR2CSTR(text),
	                   &x, &y, &w, &h, &dx, &dy);
	return rb_ary_new3(6, rb_float_new(x), rb_float_new(y),
	                      rb_float_new(w), rb_float_new(h),
	                      rb_float_new(dx), rb_float_new(dy));
}

/* Ruby-style functions. */
static VALUE
rcairo_stack(VALUE vself) {
	cairo_t *cr = rcairo_get_cairo(vself);
	cairo_save(cr);
	rb_yield(Qnil);
	cairo_restore(cr);
	return Qnil;
}

static VALUE
rcairo_run_path_func(VALUE vself, void (*f)(cairo_t *cr)) {
	cairo_t *cr = rcairo_get_cairo(vself);
	if (rb_block_given_p()) {
		cairo_new_path(cr);
		rb_yield(Qnil);
	}
	f(cr);
	return Qnil;
}

static VALUE
rcairo_stroke(VALUE vself) {
	return rcairo_run_path_func(vself, cairo_stroke);
}

static VALUE
rcairo_fill(VALUE vself) {
	return rcairo_run_path_func(vself, cairo_fill);
}

cairo_matrix_t*
rmatrix_get_matrix(VALUE vmatrix) {
	cairo_matrix_t *cr;
	Data_Get_Struct(vmatrix, cairo_matrix_t, cr);
	return cr;
}
VALUE
rmatrix_new() {
	cairo_matrix_t *cr = cairo_matrix_create();
	//cairo_matrix_reference(cr);
	return Data_Wrap_Struct(cCairoMatrix, NULL, cairo_matrix_destroy, cr);
}
static VALUE
rmatrix_rmatrix_new(VALUE class) {
	return rmatrix_new();
}

cairo_surface_t*
rsurface_get_surface(VALUE vsurface) {
	cairo_surface_t *cr;
	Data_Get_Struct(vsurface, cairo_surface_t, cr);
	return cr;
}
VALUE
rsurface_new_from(cairo_surface_t *surf) {
	cairo_surface_reference(surf);
	return Data_Wrap_Struct(cCairoSurface, NULL, cairo_surface_destroy, surf);
}


/*static VALUE
rcairo_surface_new_for_image(VALUE class, VALUE image) {
	cairo_surface_t *surface;
	rcairoImage *img;
	Data_Get_Struct(image, rcairoImage, img);
	surface = cairo_surface_create_for_image(img->data, img->format,
	                                  img->width, img->height, img->stride);
	return Data_Wrap_Struct(cCairoSurface, NULL, cairo_surface_destroy, surface);
}*/

void
Init_cairo() {
	mCairo = rb_define_module("Cairo");

	cCairo = gen_Cairo();
	rb_define_singleton_method(cCairo, "new", rcairo_rcairo_new, 0);
	rb_define_method(cCairo, "dup", rcairo_dup, 0);
	rb_define_method(cCairo, "target_image=", rcairo_set_target_image, 1);
	rb_define_method(cCairo, "set_dash", rcairo_set_dash, 2);
	rb_define_method(cCairo, "transform_point", rcairo_transform_point, 1);
	rb_define_method(cCairo, "transform_distance", rcairo_transform_distance, 1);
	rb_define_method(cCairo, "inverse_transform_point", rcairo_inverse_transform_point, 1);
	rb_define_method(cCairo, "inverse_transform_distance", rcairo_inverse_transform_distance, 1);
	rb_define_method(cCairo, "text_extents", rcairo_text_extents, 1);

	rb_define_method(cCairo, "stack", rcairo_stack, 0);
	rb_define_method(cCairo, "stroke", rcairo_stroke, 0);
	rb_define_method(cCairo, "fill", rcairo_fill, 0);

	cCairoMatrix = gen_CairoMatrix();

	cCairoSurface = gen_CairoSurface();

	xlib_init();
	rcairo_image_init();

	cCairoSurface = rb_define_class_under(mCairo, "Surface", rb_cObject);
	//rb_define_singleton_method(cCairoSurface, "new_for_image", rcairo_surface_new_for_image, 1);
}


--- NEW FILE: extconf.rb ---
#!/usr/bin/env ruby

require 'mkmf'
$CFLAGS << " -g -Wall `pkg-config --cflags cairo`"
$LDFLAGS << " `pkg-config --libs cairo`"
create_makefile("cairo")

--- NEW FILE: image.c ---
/* vim: set ts=4 sw=4 noet : */

#include "shared.h"

VALUE cCairoImage;
VALUE eCairoImageFormat;

static void
rcairo_image_free(RCairoImage *img) {
	free(img->data); free(img);
}

RCairoImage*
rcairo_image_get_image(VALUE vimage) {
	RCairoImage *img;
	Data_Get_Struct(vimage, RCairoImage, img);
	return img;
}

static VALUE
rcairo_image_new(VALUE class, VALUE vformat, VALUE vwidth, VALUE vheight, VALUE vstride) {
	int format = FIX2INT(vformat);
	int bpp = 0;
	int datasize;
	RCairoImage *img;
	
	/* XXX only supports one format. */
	format = CAIRO_FORMAT_ARGB32;
	switch (format) {
		case CAIRO_FORMAT_ARGB32:
			bpp = 32;
			break;
		default:
			rb_raise(eCairoImageFormat, "unimplemented image format %d\n", format);
			return Qnil;
	}
	img = malloc(sizeof(RCairoImage));
	img->format = format;
	img->width  = FIX2INT(vwidth);
	img->height = FIX2INT(vheight);
	img->stride = FIX2INT(vstride);
	datasize = img->stride * img->height * bpp/8;
	img->data = malloc(datasize);
	memset(img->data, 0, datasize);
	return Data_Wrap_Struct(cCairoImage, NULL, rcairo_image_free, img);
}

static VALUE
rcairo_image_each_pixel(VALUE self) {
	RCairoImage *img = rcairo_image_get_image(self);
	unsigned int *data;
	int x, y;

	/* XXX assumes 32bpp format and stride == width. */
	data = (unsigned int*)img->data;
	for (y = 0; y < img->height; y++) {
		for (x = 0; x < img->width; x++) {
			rb_yield(rb_ary_new3(4, INT2FIX(x), INT2FIX(y), UINT2NUM(*data)));
			data++;
		}
	}
	return Qnil;
}

void
rcairo_image_init(void) {
	cCairoImage = rb_define_class_under(mCairo, "Image", rb_cObject);
	rb_define_singleton_method(cCairoImage, "new", rcairo_image_new, 4);
	rb_define_method(cCairoImage, "each_pixel", rcairo_image_each_pixel, 0);

	eCairoImageFormat = rb_define_class_under(mCairo, "ImageFormat", rb_eException);
}


--- NEW FILE: shared.h ---
/* ruby-cairo - Ruby bindings for Cairo.
 * Copyright (C) 2003 Evan Martin <martine at danga.com>
 *
 * vim: tabstop=4 shiftwidth=4 noexpandtab :
 */

#include <ruby.h>
#include <cairo.h>

void xlib_init();
void cairo_xlib_init(void);

extern VALUE mCairo, cCairo, cCairoSurface, cCairoMatrix, cCairoImage;
extern VALUE cDisplay, eXlib;

typedef struct {
	char *data;
	cairo_format_t format;
	int width, height, stride;
} RCairoImage;

VALUE gen_Cairo(void);
VALUE gen_CairoMatrix(void);
VALUE gen_CairoSurface(void);

VALUE rcairo_display_new();
Display* rcairo_display_get_display(VALUE rdpy);

VALUE rcairo_new();
cairo_t* rcairo_get_cairo(VALUE rcairo);

void rcairo_image_init(void);
RCairoImage* rcairo_image_get_image(VALUE vimage);

VALUE rmatrix_new();
cairo_matrix_t* rmatrix_get_matrix(VALUE vmatrix);

VALUE rsurface_new_from();
cairo_surface_t* rsurface_get_surface(VALUE rcairo);

--- NEW FILE: xlib.c ---
/* ruby-cairo - Ruby bindings for Cairo.
 * Copyright (C) 2003 Evan Martin <martine at danga.com>
 *
 * vim: tabstop=4 shiftwidth=4 noexpandtab :
 */

#include "shared.h"

#include "cairo-xlib.h"

VALUE mXlib, eXlib, cDisplay, cWindow;

VALUE
rcairo_display_new() {
	Display *dpy;
	VALUE obj;

	dpy = XOpenDisplay(NULL);
	if (dpy == NULL) {
		rb_raise(eXlib, "XOpenDisplay: Unable to open display");
		return Qnil;
	}

	obj = Data_Wrap_Struct(cDisplay, 0, 0, dpy);
	rb_iv_set(obj, "@windows", rb_hash_new());
	rb_iv_set(obj, "@quit", Qfalse);

	return obj;
}
Display*
rcairo_display_get_display(VALUE rdpy) {
	Display *dpy;
	Data_Get_Struct(rdpy, Display, dpy);
	return dpy;
}

static VALUE
display_new(VALUE class) {
	return rcairo_display_new();
}

static VALUE
display_xconnection(VALUE self) {
	Display *dpy;
	Data_Get_Struct(self, Display, dpy);
	return INT2FIX(ConnectionNumber(dpy));
}
static VALUE
display_width(VALUE self) {
	Display *dpy;
	Data_Get_Struct(self, Display, dpy);
	return INT2FIX(DisplayWidth(dpy, 0));
}
static VALUE
display_height(VALUE self) {
	Display *dpy;
	Data_Get_Struct(self, Display, dpy);
	return INT2FIX(DisplayHeight(dpy, 0));
}

static void
redraw(VALUE vwin, Display *dpy, Window win) {
	XClearWindow(dpy, win);
	rb_funcall(vwin, rb_intern("draw"), 0);
}

static VALUE
display_loop(VALUE vself) {
	Display *dpy = rcairo_display_get_display(vself);
	XEvent xev;
	VALUE vwindows, vwin;

	vwindows = rb_iv_get(vself, "@windows");

	while (rb_iv_get(vself, "@quit") == Qfalse) {
		XNextEvent(dpy, &xev);

		switch(xev.type) {
		case KeyPress: {
			XKeyEvent *kev = &xev.xkey;
			unsigned int sym = XKeycodeToKeysym(dpy, kev->keycode, 0);
			vwin = rb_hash_aref(vwindows, INT2FIX(kev->window));
			if (vwin == Qnil)
				continue;
			if (sym > 255) sym = 0;
			rb_funcall(vwin, rb_intern("keypress"), 1, INT2FIX(sym));
			redraw(vwin, dpy, kev->window);
		} break;
		case ConfigureNotify: {
			XConfigureEvent *cev = &xev.xconfigure;
			vwin = rb_hash_aref(vwindows, INT2FIX(cev->window));
			if (vwin == Qnil)
				continue;
			rb_iv_set(vwin, "@width", INT2FIX(cev->width));
			rb_iv_set(vwin, "@height", INT2FIX(cev->height));
			rb_funcall(vwin, rb_intern("resize"), 0);
		} break;
		case Expose: {
			XExposeEvent *eev = &xev.xexpose;
			vwin = rb_hash_aref(vwindows, INT2FIX(eev->window));
			if (vwin == Qnil)
				continue;
			if (eev->count == 0)
				redraw(vwin, dpy, eev->window);
		} break;
		}
	}

	XCloseDisplay(dpy);

	return Qnil;
}

static VALUE
display_quit(VALUE vself) {
	rb_iv_set(vself, "@quit", Qtrue);
	return Qnil;
}

void
xlib_set_size_hints(Display *dpy, Window win, int width, int height) {
	XSizeHints hnt = {0};

	hnt.flags = USSize | PSize | PMinSize | PMaxSize;
	hnt.width      = width;
	hnt.min_width  = width;
	hnt.max_width  = width;
	hnt.height     = height;
	hnt.min_height = height;
	hnt.max_height = height;
	XSetWMNormalHints(dpy, win, &hnt);
}

static VALUE
window_create(VALUE vdpy, VALUE vwidth, VALUE vheight, VALUE vbg) {
	Display *dpy;
	Window root, win;
	int scr;
	int width, height;
	unsigned long color;

	dpy = rcairo_display_get_display(vdpy);

	XSynchronize(dpy, 1);
	root = DefaultRootWindow(dpy);
	scr = DefaultScreen(dpy);
	width = FIX2INT(vwidth);
	height = FIX2INT(vheight);

	if (vbg == Qtrue)
		color = WhitePixel(dpy, scr);
	else
		color = BlackPixel(dpy, scr);
	
	win = XCreateSimpleWindow(dpy, root, 0, 0,
	                          width, height, 0,
	                          color, color);
	
	XSelectInput(dpy, win,
		 KeyPressMask
		 |StructureNotifyMask
		 |ExposureMask);

	XMapWindow(dpy, win);
	return INT2FIX(win);
}

static VALUE
window_init(VALUE vself, VALUE vdpy, VALUE vwidth, VALUE vheight, VALUE vbg) {
	VALUE vwin, vcairo;

	rb_iv_set(vself, "@dpy", vdpy);
	vwin = window_create(vdpy, vwidth, vheight, vbg);
	rb_hash_aset(rb_iv_get(vdpy, "@windows"), vwin, vself);
	rb_iv_set(vself, "@win", vwin);

	vcairo = rcairo_new();
	rb_iv_set(vself, "@cairo", vcairo);
	cairo_set_target_drawable(rcairo_get_cairo(vcairo),
	                          rcairo_display_get_display(vdpy),
							  FIX2INT(vwin));

	return vself;
}

static VALUE
window_nop(VALUE vself) {
	return Qnil;
}

void
xlib_init() {
	VALUE mXlib = rb_define_module_under(mCairo, "Xlib");
	eXlib = rb_define_class_under(mXlib, "Exception", rb_eException);
	cDisplay = rb_define_class_under(mXlib, "Display", rb_cObject);
	rb_define_singleton_method(cDisplay, "new", display_new, 0);
	rb_define_method(cDisplay, "xconnection", display_xconnection, 0);
	rb_define_method(cDisplay, "width", display_width, 0);
	rb_define_method(cDisplay, "height", display_height, 0);
	rb_define_method(cDisplay, "mainloop", display_loop, 0);
	rb_define_method(cDisplay, "quit", display_quit, 0);

	cWindow = rb_define_class_under(mXlib, "Window", rb_cObject);
	rb_define_method(cWindow, "initialize", window_init, 4);
	rb_define_method(cWindow, "draw", window_nop, -1);
	rb_define_method(cWindow, "resize", window_nop, -1);
	rb_define_method(cWindow, "keypress", window_nop, -1);
}

Display*
xlib_dpy_from_rb(VALUE display) {
	Display *dpy;
	Data_Get_Struct(display, Display, dpy);
	return dpy;
}





More information about the cairo-commit mailing list