3 #include <gdk/gdkdrawable.h>
4 #include <gdk/gdkcairo.h>
5 #include <librsvg-2/librsvg/rsvg.h>
6 #include <librsvg-2/librsvg/rsvg-cairo.h>
10 #define PyMODINIT_FUNC void
13 static GtkWidget
*window
;
14 static GtkWidget
*drawing_area
;
15 static char ready
= 0;
17 static RsvgHandle
*rsvg
= NULL
;
19 static void draw(GtkWidget
*widget
, cairo_t
*cr
) {
20 if (rsvg
== NULL
) return;
22 double window_width
, window_height
;
23 window_width
= widget
->allocation
.width
;
24 window_height
= widget
->allocation
.height
;
26 RsvgDimensionData dimensions
;
27 rsvg_handle_get_dimensions(rsvg
, &dimensions
);
30 h
= dimensions
.height
;
32 aspect_ratio
= 1.0 * w
/ h
;
34 double page_width
, page_height
;
35 page_height
= window_height
- 8;
36 page_width
= page_height
* aspect_ratio
;
37 if (page_width
> window_width
- 8) {
38 page_width
= window_width
- 8;
39 page_height
= page_width
/ aspect_ratio
;
41 double x
= (window_width
- page_width
+ 4.) / 2.;
42 double y
= (window_height
- page_height
+ 4.) / 2.;
44 cairo_rectangle(cr
, x
, y
, page_width
, page_height
);
45 cairo_set_source_rgb(cr
, 1, 1, 1);
48 cairo_translate(cr
, x
, y
);
49 cairo_scale(cr
, page_width
/w
, page_height
/h
);
50 rsvg_handle_render_cairo(rsvg
, cr
);
53 static gboolean
expose_event(GtkWidget
*widget
, GdkEventExpose
*event
) {
57 cr
= gdk_cairo_create(widget
->window
);
58 cairo_rectangle(cr
, event
->area
.x
, event
->area
.y
, event
->area
.width
, event
->area
.height
);
67 static void *thread() {
71 window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
72 gtk_window_set_title(GTK_WINDOW(window
), "SVGFig");
73 drawing_area
= gtk_drawing_area_new();
74 gtk_container_add(GTK_CONTAINER(window
), drawing_area
);
76 g_signal_connect(GTK_OBJECT(window
), "delete_event", (GtkSignalFunc
)(gtk_main_quit
), NULL
);
77 g_signal_connect(GTK_OBJECT(drawing_area
), "expose_event", (GtkSignalFunc
)(expose_event
), NULL
);
78 gtk_widget_set_events(drawing_area
, GDK_EXPOSURE_MASK
);
80 gtk_widget_show(drawing_area
);
81 gtk_widget_show(window
);
89 static PyObject
*_viewer_str(PyObject
*self
, PyObject
*args
) {
90 char *str_source
= NULL
;
92 if (!PyArg_ParseTuple(args
, "es#", "utf-16", &str_source
, &str_size
)) {
93 PyErr_SetString(PyExc_TypeError
, "source must be an SVG string or Unicode object.");
99 if (!g_thread_create(thread
, NULL
, FALSE
, &error
)) {
100 PyErr_Format(PyExc_RuntimeError
, "Could not create GDK thread: %s", error
->message
);
101 PyMem_Free(str_source
);
107 g_object_unref(rsvg
);
111 GError
* error
= NULL
;
112 rsvg
= rsvg_handle_new_from_data((guint8
*)(str_source
), (gsize
)(str_size
), &error
);
114 PyErr_Format(PyExc_RuntimeError
, "Couldn't parse SVG: %s", error
->message
);
115 PyMem_Free(str_source
);
119 /* wait for the window to appear, and don't wait forever */
120 /* if 5 seconds are reached, don't explicitly throw an error, let */
121 /* GDK do that if it needs to */
123 time_t start
= time(NULL
);
125 time_t now
= time(NULL
);
126 if (difftime(now
, start
) > 5) break;
130 gtk_widget_queue_draw(drawing_area
);
133 PyMem_Free(str_source
);
134 return Py_BuildValue("O", Py_None
);
137 static PyMethodDef _viewer_methods
[] = {
138 {"str", ((PyCFunction
)(_viewer_str
)), METH_VARARGS
, ""},
142 PyMODINIT_FUNC
init_viewer() {
143 Py_InitModule3("_viewer", _viewer_methods
, "");