]>
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
28 #include <sys/types.h>
32 #include <X11/keysym.h>
34 #include <cairo-xlib.h>
38 struct svgtiny_diagram
*diagram
;
40 Window diagram_window
;
41 Atom wm_protocols_atom
, wm_delete_window_atom
;
49 void update_window_title(void);
51 void event_diagram_key_press(XKeyEvent
*key_event
);
52 void event_diagram_expose(const XExposeEvent
*expose_event
);
53 void render_path(cairo_t
*cr
, float scale
, struct svgtiny_shape
*path
);
54 void die(const char *message
);
60 int main(int argc
, char *argv
[])
70 fprintf(stderr
, "Usage: %s FILE\n", argv
[0]);
75 /* load file into memory buffer */
76 fd
= fopen(svg_path
, "rb");
82 if (stat(svg_path
, &sb
)) {
88 buffer
= malloc(size
);
90 fprintf(stderr
, "Unable to allocate %lld bytes\n",
95 n
= fread(buffer
, 1, size
, fd
);
103 /* create svgtiny object */
104 diagram
= svgtiny_create();
106 fprintf(stderr
, "svgtiny_create failed\n");
111 code
= svgtiny_parse(diagram
, buffer
, size
, svg_path
, 1000, 1000);
112 if (code
!= svgtiny_OK
) {
113 fprintf(stderr
, "svgtiny_parse failed: ");
115 case svgtiny_OUT_OF_MEMORY
:
116 fprintf(stderr
, "svgtiny_OUT_OF_MEMORY");
118 case svgtiny_LIBDOM_ERROR
:
119 fprintf(stderr
, "svgtiny_LIBDOM_ERROR");
121 case svgtiny_NOT_SVG
:
122 fprintf(stderr
, "svgtiny_NOT_SVG");
124 case svgtiny_SVG_ERROR
:
125 fprintf(stderr
, "svgtiny_SVG_ERROR: line %i: %s",
127 diagram
->error_message
);
129 case svgtiny_LIBCSS_ERROR
:
130 fprintf(stderr
, "svgtiny_LIBCSS_ERROR");
133 fprintf(stderr
, "unknown svgtiny_code %i", code
);
136 fprintf(stderr
, "\n");
141 /*printf("viewbox 0 0 %u %u\n",
142 diagram->width, diagram->height);*/
151 svgtiny_free(diagram
);
158 * Initialize X11 interface.
162 display
= XOpenDisplay(NULL
);
164 die("XOpenDisplay failed: is DISPLAY set?");
166 diagram_window
= XCreateSimpleWindow(display
,
167 DefaultRootWindow(display
),
168 0, 0, diagram
->width
, diagram
->height
, 0, 0, 0);
170 update_window_title();
172 XMapWindow(display
, diagram_window
);
173 XSelectInput(display
, diagram_window
,
177 StructureNotifyMask
);
179 wm_protocols_atom
= XInternAtom(display
, "WM_PROTOCOLS", False
);
180 wm_delete_window_atom
= XInternAtom(display
, "WM_DELETE_WINDOW", False
);
181 XSetWMProtocols(display
, diagram_window
, &wm_delete_window_atom
, 1);
186 * Free X11 interface.
190 XCloseDisplay(display
);
195 * Update window title to show current state.
197 void update_window_title(void)
203 svg_path_copy
= strdup(svg_path
);
204 if (!svg_path_copy
) {
205 fprintf(stderr
, "out of memory\n");
209 base_name
= basename(svg_path_copy
);
211 snprintf(title
, sizeof title
, "%s (%i%%) - svgtiny",
212 base_name
, (int) roundf(scale
* 100.0));
214 XStoreName(display
, diagram_window
, title
);
221 * Handle an X11 event.
226 XNextEvent(display
, &event
);
228 switch (event
.type
) {
230 if (event
.xkey
.window
== diagram_window
) {
231 event_diagram_key_press(&event
.xkey
);
235 if (event
.xexpose
.window
== diagram_window
) {
236 event_diagram_expose(&event
.xexpose
);
240 if (event
.xclient
.message_type
== wm_protocols_atom
&&
241 event
.xclient
.format
== 32 &&
242 (Atom
) event
.xclient
.data
.l
[0] ==
243 wm_delete_window_atom
)
247 /*printf("unknown event %i\n", event.type);*/
254 * Handle an X11 KeyPress event in the diagram window.
256 void event_diagram_key_press(XKeyEvent
*key_event
)
259 float new_scale
= scale
;
260 unsigned int width
, height
;
262 key_sym
= XLookupKeysym(key_event
, 0);
298 else if (5 < new_scale
)
301 if (new_scale
== scale
)
305 width
= diagram
->width
* scale
;
306 height
= diagram
->height
* scale
;
311 XResizeWindow(display
, diagram_window
, width
, height
);
312 XClearArea(display
, diagram_window
, 0, 0, 0, 0, True
);
313 update_window_title();
318 * Handle an X11 Expose event of the diagram window.
320 void event_diagram_expose(const XExposeEvent
*expose_event
)
322 cairo_surface_t
*surface
;
324 cairo_status_t status
;
327 if (expose_event
->count
!= 0)
330 surface
= cairo_xlib_surface_create(display
, diagram_window
,
331 DefaultVisual(display
, DefaultScreen(display
)),
332 diagram
->width
* scale
, diagram
->height
* scale
);
334 fprintf(stderr
, "cairo_xlib_surface_create failed\n");
338 cr
= cairo_create(surface
);
339 status
= cairo_status(cr
);
340 if (status
!= CAIRO_STATUS_SUCCESS
) {
341 fprintf(stderr
, "cairo_create failed: %s\n",
342 cairo_status_to_string(status
));
344 cairo_surface_destroy(surface
);
348 cairo_set_source_rgb(cr
, 1, 1, 1);
351 for (i
= 0; i
!= diagram
->shape_count
; i
++) {
352 if (diagram
->shape
[i
].path
) {
353 render_path(cr
, scale
, &diagram
->shape
[i
]);
355 } else if (diagram
->shape
[i
].text
) {
356 cairo_set_source_rgb(cr
,
357 svgtiny_RED(diagram
->shape
[i
].stroke
) / 255.0,
358 svgtiny_GREEN(diagram
->shape
[i
].stroke
) / 255.0,
359 svgtiny_BLUE(diagram
->shape
[i
].stroke
) / 255.0);
361 scale
* diagram
->shape
[i
].text_x
,
362 scale
* diagram
->shape
[i
].text_y
);
363 cairo_show_text(cr
, diagram
->shape
[i
].text
);
367 status
= cairo_status(cr
);
368 if (status
!= CAIRO_STATUS_SUCCESS
) {
369 fprintf(stderr
, "cairo error: %s\n",
370 cairo_status_to_string(status
));
372 cairo_surface_destroy(surface
);
377 cairo_surface_destroy(surface
);
382 * Render an svgtiny path using cairo.
384 void render_path(cairo_t
*cr
, float scale
, struct svgtiny_shape
*path
)
389 for (j
= 0; j
!= path
->path_length
; ) {
390 switch ((int) path
->path
[j
]) {
391 case svgtiny_PATH_MOVE
:
393 scale
* path
->path
[j
+ 1],
394 scale
* path
->path
[j
+ 2]);
397 case svgtiny_PATH_CLOSE
:
398 cairo_close_path(cr
);
401 case svgtiny_PATH_LINE
:
403 scale
* path
->path
[j
+ 1],
404 scale
* path
->path
[j
+ 2]);
407 case svgtiny_PATH_BEZIER
:
409 scale
* path
->path
[j
+ 1],
410 scale
* path
->path
[j
+ 2],
411 scale
* path
->path
[j
+ 3],
412 scale
* path
->path
[j
+ 4],
413 scale
* path
->path
[j
+ 5],
414 scale
* path
->path
[j
+ 6]);
422 if (path
->fill
!= svgtiny_TRANSPARENT
) {
423 cairo_set_source_rgb(cr
,
424 svgtiny_RED(path
->fill
) / 255.0,
425 svgtiny_GREEN(path
->fill
) / 255.0,
426 svgtiny_BLUE(path
->fill
) / 255.0);
427 cairo_fill_preserve(cr
);
429 if (path
->stroke
!= svgtiny_TRANSPARENT
) {
430 cairo_set_source_rgb(cr
,
431 svgtiny_RED(path
->stroke
) / 255.0,
432 svgtiny_GREEN(path
->stroke
) / 255.0,
433 svgtiny_BLUE(path
->stroke
) / 255.0);
434 cairo_set_line_width(cr
, scale
* path
->stroke_width
);
435 cairo_stroke_preserve(cr
);
441 * Exit with fatal error.
443 void die(const char *message
)
445 fprintf(stderr
, "%s\n", message
);