1 #define __SPSVGVIEW_C__
3 /*
4 * Inkscape - an ambitious vector drawing program
5 *
6 * Authors:
7 * Lauris Kaplinski <lauris@kaplinski.com>
8 * Frank Felfe <innerspace@iname.com>
9 * Davide Puricelli <evo@debian.org>
10 * Mitsuru Oka <oka326@parkcity.ne.jp>
11 * Masatake YAMATO <jet@gyve.org>
12 * F.J.Franklin <F.J.Franklin@sheffield.ac.uk>
13 * Michael Meeks <michael@helixcode.com>
14 * Chema Celorio <chema@celorio.com>
15 * Pawel Palucha
16 * ... and various people who have worked with various projects
17 *
18 * Copyright (C) 1999-2002 authors
19 * Copyright (C) 2001-2002 Ximian, Inc.
20 *
21 * Inkscape authors:
22 * Johan Ceuppens
23 *
24 * Copyright (C) 2004 Inkscape authors
25 *
26 * Released under GNU GPL, read the file 'COPYING' for more information
27 */
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
34 #include <string.h>
35 #include <sys/stat.h>
36 #include <locale.h>
38 #include <glib/gmem.h>
39 #include <libnr/nr-macros.h>
41 #include <libxml/tree.h>
42 #include <gdk/gdkkeysyms.h>
43 #include <gtk/gtkmain.h>
44 #include <gtk/gtkstock.h>
45 #include <gtk/gtkwindow.h>
46 #include <gtk/gtktable.h>
47 #include <gtk/gtkbutton.h>
49 #include "gc-core.h"
50 #include "preferences.h"
52 #include <glibmm/i18n.h>
53 #include "document.h"
54 #include "svg-view.h"
55 #include "svg-view-widget.h"
57 #ifdef WITH_INKJAR
58 #include "inkjar/jar.h"
59 #endif
61 #include "inkscape-private.h"
63 Inkscape::Application *inkscape;
65 #include <iostream>
67 #ifndef HAVE_BIND_TEXTDOMAIN_CODESET
68 #define bind_textdomain_codeset(p,c)
69 #endif
71 struct SPSlideShow {
72 char **slides;
73 int size;
74 int length;
75 int current;
76 SPDocument *doc;
77 GtkWidget *view;
78 GtkWindow *window;
79 bool fullscreen;
80 };
82 static GtkWidget *sp_svgview_control_show (struct SPSlideShow *ss);
83 static void sp_svgview_show_next (struct SPSlideShow *ss);
84 static void sp_svgview_show_prev (struct SPSlideShow *ss);
85 static void sp_svgview_goto_first (struct SPSlideShow *ss);
86 static void sp_svgview_goto_last (struct SPSlideShow *ss);
88 static int sp_svgview_show_next_cb (GtkWidget *widget, void *data);
89 static int sp_svgview_show_prev_cb (GtkWidget *widget, void *data);
90 static int sp_svgview_goto_first_cb (GtkWidget *widget, void *data);
91 static int sp_svgview_goto_last_cb (GtkWidget *widget, void *data);
92 #ifdef WITH_INKJAR
93 static bool is_jar(char const *filename);
94 #endif
95 static void usage();
97 static GtkWidget *ctrlwin = NULL;
99 /// Dummy functions to keep linker happy
100 int sp_main_gui (int, char const**) { return 0; }
101 int sp_main_console (int, char const**) { return 0; }
103 static int
104 sp_svgview_main_delete (GtkWidget *widget, GdkEvent *event, struct SPSlideShow *ss)
105 {
106 gtk_main_quit ();
107 return FALSE;
108 }
110 static int
111 sp_svgview_main_key_press (GtkWidget *widget, GdkEventKey *event, struct SPSlideShow *ss)
112 {
113 switch (event->keyval) {
114 case GDK_Up:
115 sp_svgview_goto_first(ss);
116 break;
117 case GDK_Down:
118 sp_svgview_goto_last(ss);
119 break;
120 case GDK_F11:
121 #ifdef HAVE_GTK_WINDOW_FULLSCREEN
122 if (ss->fullscreen) {
123 gtk_window_unfullscreen ((GtkWindow *) widget);
124 ss->fullscreen = false;
125 } else {
126 gtk_window_fullscreen ((GtkWindow *) widget);
127 ss->fullscreen = true;
128 }
129 #else
130 std::cout<<"Your GTK+ does not support fullscreen mode. Upgrade to 2.2."<<std::endl;
131 #endif
132 break;
133 case GDK_Return:
134 sp_svgview_control_show (ss);
135 break;
136 case GDK_KP_Page_Down:
137 case GDK_Page_Down:
138 case GDK_Right:
139 case GDK_space:
140 sp_svgview_show_next (ss);
141 break;
142 case GDK_KP_Page_Up:
143 case GDK_Page_Up:
144 case GDK_Left:
145 sp_svgview_show_prev (ss);
146 break;
147 case GDK_Escape:
148 case GDK_q:
149 case GDK_Q:
150 gtk_main_quit();
151 break;
152 default:
153 break;
154 }
155 gtk_window_set_title(GTK_WINDOW(widget), SP_DOCUMENT_NAME(ss->doc));
156 return FALSE;
157 }
159 int
160 main (int argc, const char **argv)
161 {
162 if (argc == 1) {
163 usage();
164 }
166 struct SPSlideShow ss;
168 GtkWidget *w;
169 int i;
171 bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
172 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
173 textdomain (GETTEXT_PACKAGE);
175 LIBXML_TEST_VERSION
177 Inkscape::GC::init();
178 Inkscape::Preferences::loadSkeleton();
180 gtk_init (&argc, (char ***) &argv);
182 #ifdef lalaWITH_MODULES
183 g_warning ("Have to autoinit modules (lauris)");
184 sp_modulesys_init();
185 #endif /* WITH_MODULES */
187 /* We must set LC_NUMERIC to default, or otherwise */
188 /* we'll end with localised SVG files :-( */
190 setlocale (LC_NUMERIC, "C");
192 ss.size = 32;
193 ss.length = 0;
194 ss.current = 0;
195 ss.slides = g_new (char *, ss.size);
196 ss.current = 0;
197 ss.doc = NULL;
198 ss.view = NULL;
199 ss.fullscreen = false;
201 inkscape = (Inkscape::Application *)g_object_new (SP_TYPE_INKSCAPE, NULL);
202 Inkscape::Preferences::load();
204 for (i = 1; i < argc; i++) {
205 struct stat st;
206 if (stat (argv[i], &st)
207 || !S_ISREG (st.st_mode)
208 || (st.st_size < 64)) {
209 fprintf(stderr, "could not open file %s\n", argv[i]);
210 } else {
212 #ifdef WITH_INKJAR
213 if (is_jar(argv[i])) {
214 Inkjar::JarFileReader jar_file_reader(argv[i]);
215 for (;;) {
216 GByteArray *gba = jar_file_reader.get_next_file();
217 if (gba == NULL) {
218 char *c_ptr;
219 gchar *last_filename = jar_file_reader.get_last_filename();
220 if (last_filename == NULL)
221 break;
222 if ((c_ptr = std::strrchr(last_filename, '/')) != NULL) {
223 if (*(++c_ptr) == '\0') {
224 g_free(last_filename);
225 continue;
226 }
227 }
228 } else if (gba->len > 0) {
229 //::write(1, gba->data, gba->len);
230 /* Append to list */
231 if (ss.length >= ss.size) {
232 /* Expand */
233 ss.size <<= 1;
234 ss.slides = g_renew (char *, ss.slides, ss.size);
235 }
237 ss.doc = sp_document_new_from_mem ((const gchar *)gba->data,
238 gba->len,
239 TRUE);
240 gchar *last_filename = jar_file_reader.get_last_filename();
241 if (ss.doc) {
242 ss.slides[ss.length++] = strdup (last_filename);
243 sp_document_set_uri (ss.doc, strdup(last_filename));
244 }
245 g_byte_array_free(gba, TRUE);
246 g_free(last_filename);
247 } else
248 break;
249 }
250 } else {
251 #endif /* WITH_INKJAR */
252 /* Append to list */
253 if (ss.length >= ss.size) {
254 /* Expand */
255 ss.size <<= 1;
256 ss.slides = g_renew (char *, ss.slides, ss.size);
258 }
260 ss.slides[ss.length++] = strdup (argv[i]);
261 ss.doc = sp_document_new (ss.slides[ss.current], TRUE, false);
263 if (!ss.doc && ++ss.current >= ss.length) {
264 /* No loadable documents */
265 return 1;
266 }
267 #ifdef WITH_INKJAR
268 }
269 #endif
270 }
271 }
273 if(!ss.doc)
274 return 1; /* none of the slides loadable */
276 w = gtk_window_new (GTK_WINDOW_TOPLEVEL);
277 gtk_window_set_title (GTK_WINDOW (w), SP_DOCUMENT_NAME (ss.doc));
278 gtk_window_set_default_size (GTK_WINDOW (w),
279 MIN ((int)sp_document_width (ss.doc), (int)gdk_screen_width () - 64),
280 MIN ((int)sp_document_height (ss.doc), (int)gdk_screen_height () - 64));
281 gtk_window_set_policy (GTK_WINDOW (w), TRUE, TRUE, FALSE);
283 g_signal_connect (G_OBJECT (w), "delete_event", (GCallback) sp_svgview_main_delete, &ss);
284 g_signal_connect (G_OBJECT (w), "key_press_event", (GCallback) sp_svgview_main_key_press, &ss);
286 ss.view = sp_svg_view_widget_new (ss.doc);
287 sp_svg_view_widget_set_resize (SP_SVG_VIEW_WIDGET (ss.view), FALSE, sp_document_width (ss.doc), sp_document_height (ss.doc));
288 sp_document_ensure_up_to_date (ss.doc);
289 sp_document_unref (ss.doc);
290 gtk_widget_show (ss.view);
291 gtk_container_add (GTK_CONTAINER (w), ss.view);
293 gtk_widget_show (w);
295 gtk_main ();
297 return 0;
298 }
300 static int
301 sp_svgview_ctrlwin_delete (GtkWidget *widget, GdkEvent *event, void *data)
302 {
303 ctrlwin = NULL;
304 return FALSE;
305 }
307 static GtkWidget *
308 sp_svgview_control_show (struct SPSlideShow *ss)
309 {
310 if (!ctrlwin) {
311 GtkWidget *t, *b;
312 ctrlwin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
313 g_signal_connect (G_OBJECT (ctrlwin), "delete_event", (GCallback) sp_svgview_ctrlwin_delete, NULL);
314 t = gtk_table_new (1, 4, TRUE);
315 gtk_container_add ((GtkContainer *) ctrlwin, t);
316 b = gtk_button_new_from_stock (GTK_STOCK_GOTO_FIRST);
317 gtk_table_attach ((GtkTable *) t, b, 0, 1, 0, 1,
318 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
319 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
320 0, 0);
321 g_signal_connect ((GObject *) b, "clicked", (GCallback) sp_svgview_goto_first_cb, ss);
322 b = gtk_button_new_from_stock (GTK_STOCK_GO_BACK);
323 gtk_table_attach ((GtkTable *) t, b, 1, 2, 0, 1,
324 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
325 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
326 0, 0);
327 g_signal_connect (G_OBJECT(b), "clicked", (GCallback) sp_svgview_show_prev_cb, ss);
328 b = gtk_button_new_from_stock (GTK_STOCK_GO_FORWARD);
329 gtk_table_attach ((GtkTable *) t, b, 2, 3, 0, 1,
330 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
331 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
332 0, 0);
333 g_signal_connect (G_OBJECT(b), "clicked", (GCallback) sp_svgview_show_next_cb, ss);
334 b = gtk_button_new_from_stock (GTK_STOCK_GOTO_LAST);
335 gtk_table_attach ((GtkTable *) t, b, 3, 4, 0, 1,
336 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
337 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
338 0, 0);
339 g_signal_connect (G_OBJECT(b), "clicked", (GCallback) sp_svgview_goto_last_cb, ss);
340 gtk_widget_show_all (ctrlwin);
341 } else {
342 gtk_window_present ((GtkWindow *) ctrlwin);
343 }
345 return NULL;
346 }
348 static int
349 sp_svgview_show_next_cb (GtkWidget *widget, void *data)
350 {
351 sp_svgview_show_next(static_cast<struct SPSlideShow *>(data));
352 return FALSE;
353 }
355 static int
356 sp_svgview_show_prev_cb (GtkWidget *widget, void *data)
357 {
358 sp_svgview_show_prev(static_cast<struct SPSlideShow *>(data));
359 return FALSE;
360 }
362 static int
363 sp_svgview_goto_first_cb (GtkWidget *widget, void *data)
364 {
365 sp_svgview_goto_first(static_cast<struct SPSlideShow *>(data));
366 return FALSE;
367 }
369 static int
370 sp_svgview_goto_last_cb (GtkWidget *widget, void *data)
371 {
372 sp_svgview_goto_last(static_cast<struct SPSlideShow *>(data));
373 return FALSE;
374 }
376 static void
377 sp_svgview_show_next (struct SPSlideShow *ss)
378 {
379 SPDocument *doc;
380 int current;
381 doc = NULL;
382 current = ss->current;
383 while (!doc && (current < ss->length - 1)) {
384 doc = sp_document_new (ss->slides[++current], TRUE, false);
385 }
386 if (doc) {
387 reinterpret_cast<SPSVGView*>(SP_VIEW_WIDGET_VIEW (ss->view))->setDocument (doc);
388 sp_document_ensure_up_to_date (doc);
389 ss->doc = doc;
390 ss->current = current;
391 }
392 }
394 static void
395 sp_svgview_show_prev (struct SPSlideShow *ss)
396 {
397 SPDocument *doc;
398 int current;
399 doc = NULL;
400 current = ss->current;
401 while (!doc && (current > 0)) {
402 doc = sp_document_new (ss->slides[--current], TRUE, false);
403 }
404 if (doc) {
405 reinterpret_cast<SPSVGView*>(SP_VIEW_WIDGET_VIEW (ss->view))->setDocument (doc);
406 sp_document_ensure_up_to_date (doc);
407 ss->doc = doc;
408 ss->current = current;
409 }
410 }
412 static void
413 sp_svgview_goto_first (struct SPSlideShow *ss)
414 {
415 SPDocument *doc = NULL;
416 int current = 0;
417 for ( ; !doc && (current < ss->length); current++) {
418 doc = sp_document_new (ss->slides[current], TRUE, false);
419 }
420 if (doc) {
421 reinterpret_cast<SPSVGView*>(SP_VIEW_WIDGET_VIEW (ss->view))->setDocument (doc);
422 sp_document_ensure_up_to_date (doc);
423 ss->doc = doc;
424 ss->current = current;
425 }
426 }
428 static void
429 sp_svgview_goto_last (struct SPSlideShow *ss)
430 {
431 SPDocument *doc = NULL;
432 int current = ss->length - 1;
433 for ( ; !doc && (current >= 0); current--) {
434 doc = sp_document_new (ss->slides[current], TRUE, false);
435 }
436 if (doc) {
437 reinterpret_cast<SPSVGView*>(SP_VIEW_WIDGET_VIEW (ss->view))->setDocument (doc);
438 sp_document_ensure_up_to_date (doc);
439 ss->doc = doc;
440 ss->current = current;
441 }
442 }
444 #ifdef WITH_INKJAR
445 static bool
446 is_jar(char const *filename)
447 {
448 /* fixme: Check MIME type or something. /usr/share/misc/file/magic suggests that checking for
449 initial string "PK\003\004" in content should suffice. */
450 size_t const filename_len = strlen(filename);
451 if (filename_len < 5) {
452 return false;
453 }
454 char const *extension = filename + filename_len - 4;
455 return ((memcmp(extension, ".jar", 4) == 0) ||
456 (memcmp(extension, ".sxw", 4) == 0) );
457 }
458 #endif /* WITH_INKJAR */
460 static void usage()
461 {
462 fprintf(stderr,
463 "Usage: inkview [FILES ...]\n"
464 "\twhere FILES are SVG (.svg or .svgz)"
465 #ifdef WITH_INKJAR
466 "or archives of SVGs (.sxw, .jar)"
467 #endif
468 "\n");
469 exit(1);
470 }
472 #ifdef XXX
473 /* TODO !!! make this temporary stub unnecessary */
474 Inkscape::Application *inkscape_get_instance() { return NULL; }
475 void inkscape_ref (void) {}
476 void inkscape_unref (void) {}
477 void inkscape_add_document (SPDocument *document) {}
478 void inkscape_remove_document (SPDocument *document) {}
479 Inkscape::XML::Node *inkscape_get_repr (Inkscape::Application *inkscape, const gchar *key) {return NULL;}
480 #endif
483 /*
484 Local Variables:
485 mode:c++
486 c-file-style:"stroustrup"
487 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
488 indent-tabs-mode:nil
489 fill-column:99
490 End:
491 */
492 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :