]>
gitweb.michael.orlitzky.com - libsvgtiny.git/blob - examples/svgtiny_display_x11.c
2 * This file is part of Libsvgtiny
3 * Licensed under the MIT License,
4 * http://opensource.org/licenses/mit-license.php
5 * Copyright 2009-2010 James Bursa <james@semichrome.net>
9 * This example loads an SVG using libsvgtiny and then displays it in an X11
12 * Functions of interest for libsvgtiny use are:
13 * main() - loads an SVG using svgtiny_create() and svgtiny_parse()
14 * event_diagram_expose() - renders the SVG by stepping through the shapes
17 * gcc -g -W -Wall -o svgtiny_display_x11 svgtiny_display_x11.c \
18 * `pkg-config --cflags --libs libsvgtiny cairo` -lX11
27 #include <sys/types.h>
31 #include <X11/keysym.h>
33 #include <cairo-xlib.h>
37 struct svgtiny_diagram
*diagram
;
39 Window diagram_window
;
40 Atom wm_protocols_atom
, wm_delete_window_atom
;
48 void update_window_title(void);
50 void event_diagram_key_press(XKeyEvent
*key_event
);
51 void event_diagram_expose(const XExposeEvent
*expose_event
);
52 void render_path(cairo_t
*cr
, float scale
, struct svgtiny_shape
*path
);
53 void die(const char *message
);
59 int main(int argc
, char *argv
[])
69 fprintf(stderr
, "Usage: %s FILE\n", argv
[0]);
74 /* load file into memory buffer */
75 fd
= fopen(svg_path
, "rb");
81 if (stat(svg_path
, &sb
)) {
87 buffer
= malloc(size
);
89 fprintf(stderr
, "Unable to allocate %lld bytes\n",
94 n
= fread(buffer
, 1, size
, fd
);
102 /* create svgtiny object */
103 diagram
= svgtiny_create();
105 fprintf(stderr
, "svgtiny_create failed\n");
110 code
= svgtiny_parse(diagram
, buffer
, size
, svg_path
, 1000, 1000);
111 if (code
!= svgtiny_OK
) {
112 fprintf(stderr
, "svgtiny_parse failed: ");
114 case svgtiny_OUT_OF_MEMORY
:
115 fprintf(stderr
, "svgtiny_OUT_OF_MEMORY");
117 case svgtiny_LIBXML_ERROR
:
118 fprintf(stderr
, "svgtiny_LIBXML_ERROR");
120 case svgtiny_NOT_SVG
:
121 fprintf(stderr
, "svgtiny_NOT_SVG");
123 case svgtiny_SVG_ERROR
:
124 fprintf(stderr
, "svgtiny_SVG_ERROR: line %i: %s",
126 diagram
->error_message
);
129 fprintf(stderr
, "unknown svgtiny_code %i", code
);
132 fprintf(stderr
, "\n");
137 /*printf("viewbox 0 0 %u %u\n",
138 diagram->width, diagram->height);*/
147 svgtiny_free(diagram
);
154 * Initialize X11 interface.
158 display
= XOpenDisplay(NULL
);
160 die("XOpenDisplay failed: is DISPLAY set?");
162 diagram_window
= XCreateSimpleWindow(display
,
163 DefaultRootWindow(display
),
164 0, 0, diagram
->width
, diagram
->height
, 0, 0, 0);
166 update_window_title();
168 XMapWindow(display
, diagram_window
);
169 XSelectInput(display
, diagram_window
,
173 StructureNotifyMask
);
175 wm_protocols_atom
= XInternAtom(display
, "WM_PROTOCOLS", False
);
176 wm_delete_window_atom
= XInternAtom(display
, "WM_DELETE_WINDOW", False
);
177 XSetWMProtocols(display
, diagram_window
, &wm_delete_window_atom
, 1);
182 * Free X11 interface.
186 XCloseDisplay(display
);
191 * Update window title to show current state.
193 void update_window_title(void)
199 svg_path_copy
= strdup(svg_path
);
200 if (!svg_path_copy
) {
201 fprintf(stderr
, "out of memory\n");
205 base_name
= basename(svg_path_copy
);
207 snprintf(title
, sizeof title
, "%s (%i%%) - svgtiny",
208 base_name
, (int) roundf(scale
* 100.0));
210 XStoreName(display
, diagram_window
, title
);
217 * Handle an X11 event.
222 XNextEvent(display
, &event
);
224 switch (event
.type
) {
226 if (event
.xkey
.window
== diagram_window
) {
227 event_diagram_key_press(&event
.xkey
);
231 if (event
.xexpose
.window
== diagram_window
) {
232 event_diagram_expose(&event
.xexpose
);
236 if (event
.xclient
.message_type
== wm_protocols_atom
&&
237 event
.xclient
.format
== 32 &&
238 (Atom
) event
.xclient
.data
.l
[0] ==
239 wm_delete_window_atom
)
243 /*printf("unknown event %i\n", event.type);*/
250 * Handle an X11 KeyPress event in the diagram window.
252 void event_diagram_key_press(XKeyEvent
*key_event
)
255 float new_scale
= scale
;
256 unsigned int width
, height
;
258 key_sym
= XLookupKeysym(key_event
, 0);
294 else if (5 < new_scale
)
297 if (new_scale
== scale
)
301 width
= diagram
->width
* scale
;
302 height
= diagram
->height
* scale
;
307 XResizeWindow(display
, diagram_window
, width
, height
);
308 XClearArea(display
, diagram_window
, 0, 0, 0, 0, True
);
309 update_window_title();
314 * Handle an X11 Expose event of the diagram window.
316 void event_diagram_expose(const XExposeEvent
*expose_event
)
318 cairo_surface_t
*surface
;
320 cairo_status_t status
;
323 if (expose_event
->count
!= 0)
326 surface
= cairo_xlib_surface_create(display
, diagram_window
,
327 DefaultVisual(display
, DefaultScreen(display
)),
328 diagram
->width
* scale
, diagram
->height
* scale
);
330 fprintf(stderr
, "cairo_xlib_surface_create failed\n");
334 cr
= cairo_create(surface
);
335 status
= cairo_status(cr
);
336 if (status
!= CAIRO_STATUS_SUCCESS
) {
337 fprintf(stderr
, "cairo_create failed: %s\n",
338 cairo_status_to_string(status
));
340 cairo_surface_destroy(surface
);
344 cairo_set_source_rgb(cr
, 1, 1, 1);
347 for (i
= 0; i
!= diagram
->shape_count
; i
++) {
348 if (diagram
->shape
[i
].path
) {
349 render_path(cr
, scale
, &diagram
->shape
[i
]);
351 } else if (diagram
->shape
[i
].text
) {
352 cairo_set_source_rgb(cr
,
353 svgtiny_RED(diagram
->shape
[i
].stroke
) / 255.0,
354 svgtiny_GREEN(diagram
->shape
[i
].stroke
) / 255.0,
355 svgtiny_BLUE(diagram
->shape
[i
].stroke
) / 255.0);
357 scale
* diagram
->shape
[i
].text_x
,
358 scale
* diagram
->shape
[i
].text_y
);
359 cairo_show_text(cr
, diagram
->shape
[i
].text
);
363 status
= cairo_status(cr
);
364 if (status
!= CAIRO_STATUS_SUCCESS
) {
365 fprintf(stderr
, "cairo error: %s\n",
366 cairo_status_to_string(status
));
368 cairo_surface_destroy(surface
);
373 cairo_surface_destroy(surface
);
378 * Render an svgtiny path using cairo.
380 void render_path(cairo_t
*cr
, float scale
, struct svgtiny_shape
*path
)
385 for (j
= 0; j
!= path
->path_length
; ) {
386 switch ((int) path
->path
[j
]) {
387 case svgtiny_PATH_MOVE
:
389 scale
* path
->path
[j
+ 1],
390 scale
* path
->path
[j
+ 2]);
393 case svgtiny_PATH_CLOSE
:
394 cairo_close_path(cr
);
397 case svgtiny_PATH_LINE
:
399 scale
* path
->path
[j
+ 1],
400 scale
* path
->path
[j
+ 2]);
403 case svgtiny_PATH_BEZIER
:
405 scale
* path
->path
[j
+ 1],
406 scale
* path
->path
[j
+ 2],
407 scale
* path
->path
[j
+ 3],
408 scale
* path
->path
[j
+ 4],
409 scale
* path
->path
[j
+ 5],
410 scale
* path
->path
[j
+ 6]);
418 if (path
->fill
!= svgtiny_TRANSPARENT
) {
419 cairo_set_source_rgb(cr
,
420 svgtiny_RED(path
->fill
) / 255.0,
421 svgtiny_GREEN(path
->fill
) / 255.0,
422 svgtiny_BLUE(path
->fill
) / 255.0);
423 cairo_fill_preserve(cr
);
425 if (path
->stroke
!= svgtiny_TRANSPARENT
) {
426 cairo_set_source_rgb(cr
,
427 svgtiny_RED(path
->stroke
) / 255.0,
428 svgtiny_GREEN(path
->stroke
) / 255.0,
429 svgtiny_BLUE(path
->stroke
) / 255.0);
430 cairo_set_line_width(cr
, scale
* path
->stroke_width
);
431 cairo_stroke_preserve(cr
);
437 * Exit with fatal error.
439 void die(const char *message
)
441 fprintf(stderr
, "%s\n", message
);