1 /*
2 * Inkscape - an ambitious vector drawing program
3 *
4 * Authors:
5 * Lauris Kaplinski <lauris@kaplinski.com>
6 * Frank Felfe <innerspace@iname.com>
7 * Davide Puricelli <evo@debian.org>
8 * Mitsuru Oka <oka326@parkcity.ne.jp>
9 * Masatake YAMATO <jet@gyve.org>
10 * F.J.Franklin <F.J.Franklin@sheffield.ac.uk>
11 * Michael Meeks <michael@helixcode.com>
12 * Chema Celorio <chema@celorio.com>
13 * Pawel Palucha
14 * ... and various people who have worked with various projects
15 * Abhishek Sharma
16 *
17 * Copyright (C) 1999-2002 authors
18 * Copyright (C) 2001-2002 Ximian, Inc.
19 *
20 * Inkscape authors:
21 * Johan Ceuppens
22 *
23 * Copyright (C) 2004 Inkscape authors
24 *
25 * Released under GNU GPL, read the file 'COPYING' for more information
26 */
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
33 #ifdef HAVE_GETOPT_H
34 #include <getopt.h>
35 #endif
37 #include <string.h>
38 #include <sys/stat.h>
39 #include <locale.h>
41 #include <glib/gmem.h>
42 #include <libnr/nr-macros.h>
44 // #include <stropts.h>
46 #include <libxml/tree.h>
47 #include <gdk/gdkkeysyms.h>
48 #include <gtk/gtkmain.h>
49 #include <gtk/gtkstock.h>
50 #include <gtk/gtkwindow.h>
51 #include <gtk/gtktable.h>
52 #include <gtk/gtkbutton.h>
54 #include <gtkmm/main.h>
56 #include "gc-core.h"
57 #include "preferences.h"
59 #include <glibmm/i18n.h>
60 #include "document.h"
61 #include "svg-view.h"
62 #include "svg-view-widget.h"
64 #ifdef WITH_INKJAR
65 #include "io/inkjar.h"
66 #endif
68 #include "inkscape-private.h"
70 Inkscape::Application *inkscape;
72 #include <iostream>
74 #ifndef HAVE_BIND_TEXTDOMAIN_CODESET
75 #define bind_textdomain_codeset(p,c)
76 #endif
78 extern char *optarg;
79 extern int optind, opterr;
81 struct SPSlideShow {
82 char **slides;
83 int size;
84 int length;
85 int current;
86 SPDocument *doc;
87 GtkWidget *view;
88 GtkWidget *window;
89 bool fullscreen;
90 int timer;
91 };
93 static GtkWidget *sp_svgview_control_show (struct SPSlideShow *ss);
94 static void sp_svgview_show_next (struct SPSlideShow *ss);
95 static void sp_svgview_show_prev (struct SPSlideShow *ss);
96 static void sp_svgview_goto_first (struct SPSlideShow *ss);
97 static void sp_svgview_goto_last (struct SPSlideShow *ss);
99 static int sp_svgview_show_next_cb (GtkWidget *widget, void *data);
100 static int sp_svgview_show_prev_cb (GtkWidget *widget, void *data);
101 static int sp_svgview_goto_first_cb (GtkWidget *widget, void *data);
102 static int sp_svgview_goto_last_cb (GtkWidget *widget, void *data);
103 #ifdef WITH_INKJAR
104 static bool is_jar(char const *filename);
105 #endif
106 static void usage();
108 static GtkWidget *ctrlwin = NULL;
110 /// Dummy functions to keep linker happy
111 int sp_main_gui (int, char const**) { return 0; }
112 int sp_main_console (int, char const**) { return 0; }
114 static int
115 sp_svgview_main_delete (GtkWidget */*widget*/, GdkEvent */*event*/, struct SPSlideShow */*ss*/)
116 {
117 gtk_main_quit ();
118 return FALSE;
119 }
121 static int
122 sp_svgview_main_key_press (GtkWidget */*widget*/, GdkEventKey *event, struct SPSlideShow *ss)
123 {
124 switch (event->keyval) {
125 case GDK_Up:
126 case GDK_Home:
127 sp_svgview_goto_first(ss);
128 break;
129 case GDK_Down:
130 case GDK_End:
131 sp_svgview_goto_last(ss);
132 break;
133 case GDK_F11:
134 #ifdef HAVE_GTK_WINDOW_FULLSCREEN
135 if (ss->fullscreen) {
136 gtk_window_unfullscreen (GTK_WINDOW(ss->window));
137 ss->fullscreen = false;
138 } else {
139 gtk_window_fullscreen (GTK_WINDOW(ss->window));
140 ss->fullscreen = true;
141 }
142 #else
143 std::cout<<"Your GTK+ does not support fullscreen mode. Upgrade to 2.2."<<std::endl;
144 #endif
145 break;
146 case GDK_Return:
147 sp_svgview_control_show (ss);
148 break;
149 case GDK_KP_Page_Down:
150 case GDK_Page_Down:
151 case GDK_Right:
152 case GDK_space:
153 sp_svgview_show_next (ss);
154 break;
155 case GDK_KP_Page_Up:
156 case GDK_Page_Up:
157 case GDK_Left:
158 case GDK_BackSpace:
159 sp_svgview_show_prev (ss);
160 break;
161 case GDK_Escape:
162 case GDK_q:
163 case GDK_Q:
164 gtk_main_quit();
165 break;
166 default:
167 break;
168 }
169 gtk_window_set_title(GTK_WINDOW(ss->window), ss->doc->getName());
170 return TRUE;
171 }
173 int
174 main (int argc, const char **argv)
175 {
176 if (argc == 1) {
177 usage();
178 }
180 // Prevents errors like "Unable to wrap GdkPixbuf..." (in nr-filter-image.cpp for example)
181 Gtk::Main::init_gtkmm_internals();
183 Gtk::Main main_instance (&argc, const_cast<char ***>(&argv));
185 struct SPSlideShow ss;
187 int option,
188 num_parsed_options = 0;
190 // the list of arguments is in the net line
191 while ((option = getopt(argc, (char* const* )argv, "t:")) != -1)
192 {
193 switch(option) {
194 case 't': // for timer
195 // fprintf(stderr, "set timer arg %s\n", optarg );
196 ss.timer = atoi(optarg);
197 num_parsed_options += 2; // 2 because of flag + option
198 break;
199 case '?':
200 default:
201 usage();
202 }
203 }
205 GtkWidget *w;
206 int i;
208 bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
209 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
210 textdomain (GETTEXT_PACKAGE);
212 LIBXML_TEST_VERSION
214 Inkscape::GC::init();
215 Inkscape::Preferences::get(); // ensure preferences are initialized
217 gtk_init (&argc, (char ***) &argv);
219 #ifdef lalaWITH_MODULES
220 g_warning ("Have to autoinit modules (lauris)");
221 sp_modulesys_init();
222 #endif /* WITH_MODULES */
224 /* We must set LC_NUMERIC to default, or otherwise */
225 /* we'll end with localised SVG files :-( */
227 setlocale (LC_NUMERIC, "C");
229 ss.size = 32;
230 ss.length = 0;
231 ss.current = 0;
232 ss.slides = g_new (char *, ss.size);
233 ss.current = 0;
234 ss.doc = NULL;
235 ss.view = NULL;
236 ss.fullscreen = false;
238 inkscape = (Inkscape::Application *)g_object_new (SP_TYPE_INKSCAPE, NULL);
240 // starting at where the commandline options stopped parsing because
241 // we want all the files to be in the list
242 for (i = num_parsed_options + 1 ; i < argc; i++) {
243 struct stat st;
244 if (stat (argv[i], &st)
245 || !S_ISREG (st.st_mode)
246 || (st.st_size < 64)) {
247 fprintf(stderr, "could not open file %s\n", argv[i]);
248 } else {
250 #ifdef WITH_INKJAR
251 if (is_jar(argv[i])) {
252 Inkjar::JarFileReader jar_file_reader(argv[i]);
253 for (;;) {
254 GByteArray *gba = jar_file_reader.get_next_file();
255 if (gba == NULL) {
256 char *c_ptr;
257 gchar *last_filename = jar_file_reader.get_last_filename();
258 if (last_filename == NULL)
259 break;
260 if ((c_ptr = std::strrchr(last_filename, '/')) != NULL) {
261 if (*(++c_ptr) == '\0') {
262 g_free(last_filename);
263 continue;
264 }
265 }
266 } else if (gba->len > 0) {
267 //::write(1, gba->data, gba->len);
268 /* Append to list */
269 if (ss.length >= ss.size) {
270 /* Expand */
271 ss.size <<= 1;
272 ss.slides = g_renew (char *, ss.slides, ss.size);
273 }
275 ss.doc = SPDocument::createNewDocFromMem ((const gchar *)gba->data,
276 gba->len,
277 TRUE);
278 gchar *last_filename = jar_file_reader.get_last_filename();
279 if (ss.doc) {
280 ss.slides[ss.length++] = strdup (last_filename);
281 (ss.doc)->setUri (strdup(last_filename));
282 }
283 g_byte_array_free(gba, TRUE);
284 g_free(last_filename);
285 } else
286 break;
287 }
288 } else {
289 #endif /* WITH_INKJAR */
290 /* Append to list */
291 if (ss.length >= ss.size) {
292 /* Expand */
293 ss.size <<= 1;
294 ss.slides = g_renew (char *, ss.slides, ss.size);
296 }
298 ss.slides[ss.length++] = strdup (argv[i]);
300 if (!ss.doc) {
301 ss.doc = SPDocument::createNewDoc (ss.slides[ss.current], TRUE, false);
302 if (!ss.doc)
303 ++ss.current;
304 }
305 #ifdef WITH_INKJAR
306 }
307 #endif
308 }
309 }
311 if(!ss.doc)
312 return 1; /* none of the slides loadable */
314 w = gtk_window_new (GTK_WINDOW_TOPLEVEL);
315 gtk_window_set_title( GTK_WINDOW(w), ss.doc->getName() );
316 gtk_window_set_default_size (GTK_WINDOW (w),
317 MIN ((int)(ss.doc)->getWidth (), (int)gdk_screen_width () - 64),
318 MIN ((int)(ss.doc)->getHeight (), (int)gdk_screen_height () - 64));
319 gtk_window_set_policy (GTK_WINDOW (w), TRUE, TRUE, FALSE);
320 ss.window = w;
322 g_signal_connect (G_OBJECT (w), "delete_event", (GCallback) sp_svgview_main_delete, &ss);
323 g_signal_connect (G_OBJECT (w), "key_press_event", (GCallback) sp_svgview_main_key_press, &ss);
325 (ss.doc)->ensureUpToDate();
326 ss.view = sp_svg_view_widget_new (ss.doc);
327 (ss.doc)->doUnref ();
328 sp_svg_view_widget_set_resize (SP_SVG_VIEW_WIDGET (ss.view), FALSE,
329 (ss.doc)->getWidth (), (ss.doc)->getHeight ());
330 gtk_widget_show (ss.view);
331 gtk_container_add (GTK_CONTAINER (w), ss.view);
333 gtk_widget_show (w);
335 gtk_main ();
337 return 0;
338 }
340 static int
341 sp_svgview_ctrlwin_delete (GtkWidget */*widget*/, GdkEvent */*event*/, void */*data*/)
342 {
343 ctrlwin = NULL;
344 return FALSE;
345 }
347 static GtkWidget *
348 sp_svgview_control_show (struct SPSlideShow *ss)
349 {
350 if (!ctrlwin) {
351 GtkWidget *t, *b;
352 ctrlwin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
353 gtk_window_set_transient_for (GTK_WINDOW(ctrlwin), GTK_WINDOW(ss->window));
354 g_signal_connect (G_OBJECT (ctrlwin), "key_press_event", (GCallback) sp_svgview_main_key_press, ss);
355 g_signal_connect (G_OBJECT (ctrlwin), "delete_event", (GCallback) sp_svgview_ctrlwin_delete, NULL);
356 t = gtk_table_new (1, 4, TRUE);
357 gtk_container_add ((GtkContainer *) ctrlwin, t);
358 b = gtk_button_new_from_stock (GTK_STOCK_GOTO_FIRST);
359 gtk_table_attach ((GtkTable *) t, b, 0, 1, 0, 1,
360 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
361 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
362 0, 0);
363 g_signal_connect ((GObject *) b, "clicked", (GCallback) sp_svgview_goto_first_cb, ss);
364 b = gtk_button_new_from_stock (GTK_STOCK_GO_BACK);
365 gtk_table_attach ((GtkTable *) t, b, 1, 2, 0, 1,
366 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
367 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
368 0, 0);
369 g_signal_connect (G_OBJECT(b), "clicked", (GCallback) sp_svgview_show_prev_cb, ss);
370 b = gtk_button_new_from_stock (GTK_STOCK_GO_FORWARD);
371 gtk_table_attach ((GtkTable *) t, b, 2, 3, 0, 1,
372 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
373 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
374 0, 0);
375 g_signal_connect (G_OBJECT(b), "clicked", (GCallback) sp_svgview_show_next_cb, ss);
376 b = gtk_button_new_from_stock (GTK_STOCK_GOTO_LAST);
377 gtk_table_attach ((GtkTable *) t, b, 3, 4, 0, 1,
378 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
379 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
380 0, 0);
381 g_signal_connect (G_OBJECT(b), "clicked", (GCallback) sp_svgview_goto_last_cb, ss);
382 gtk_widget_show_all (ctrlwin);
383 } else {
384 gtk_window_present ((GtkWindow *) ctrlwin);
385 }
387 return NULL;
388 }
390 static int
391 sp_svgview_show_next_cb (GtkWidget */*widget*/, void *data)
392 {
393 sp_svgview_show_next(static_cast<struct SPSlideShow *>(data));
394 return FALSE;
395 }
397 static int
398 sp_svgview_show_prev_cb (GtkWidget */*widget*/, void *data)
399 {
400 sp_svgview_show_prev(static_cast<struct SPSlideShow *>(data));
401 return FALSE;
402 }
404 static int
405 sp_svgview_goto_first_cb (GtkWidget */*widget*/, void *data)
406 {
407 sp_svgview_goto_first(static_cast<struct SPSlideShow *>(data));
408 return FALSE;
409 }
411 static int
412 sp_svgview_goto_last_cb (GtkWidget */*widget*/, void *data)
413 {
414 sp_svgview_goto_last(static_cast<struct SPSlideShow *>(data));
415 return FALSE;
416 }
418 static void
419 sp_svgview_waiting_cursor(struct SPSlideShow *ss)
420 {
421 GdkCursor *waiting = gdk_cursor_new(GDK_WATCH);
422 gdk_window_set_cursor(GTK_WIDGET(ss->window)->window, waiting);
423 gdk_cursor_unref(waiting);
424 if (ctrlwin) {
425 GdkCursor *waiting = gdk_cursor_new(GDK_WATCH);
426 gdk_window_set_cursor(GTK_WIDGET(ctrlwin)->window, waiting);
427 gdk_cursor_unref(waiting);
428 }
429 while(gtk_events_pending())
430 gtk_main_iteration();
431 }
433 static void
434 sp_svgview_normal_cursor(struct SPSlideShow *ss)
435 {
436 gdk_window_set_cursor(GTK_WIDGET(ss->window)->window, NULL);
437 if (ctrlwin) {
438 gdk_window_set_cursor(GTK_WIDGET(ctrlwin)->window, NULL);
439 }
440 }
442 static void
443 sp_svgview_set_document(struct SPSlideShow *ss, SPDocument *doc, int current)
444 {
445 if (doc && doc != ss->doc) {
446 doc->ensureUpToDate();
447 reinterpret_cast<SPSVGView*>(SP_VIEW_WIDGET_VIEW (ss->view))->setDocument (doc);
448 ss->doc = doc;
449 ss->current = current;
450 }
451 }
453 static void
454 sp_svgview_show_next (struct SPSlideShow *ss)
455 {
456 sp_svgview_waiting_cursor(ss);
458 SPDocument *doc = NULL;
459 int current = ss->current;
460 while (!doc && (current < ss->length - 1)) {
461 doc = SPDocument::createNewDoc (ss->slides[++current], TRUE, false);
462 }
464 sp_svgview_set_document(ss, doc, current);
466 sp_svgview_normal_cursor(ss);
467 }
469 static void
470 sp_svgview_show_prev (struct SPSlideShow *ss)
471 {
472 sp_svgview_waiting_cursor(ss);
474 SPDocument *doc = NULL;
475 int current = ss->current;
476 while (!doc && (current > 0)) {
477 doc = SPDocument::createNewDoc (ss->slides[--current], TRUE, false);
478 }
480 sp_svgview_set_document(ss, doc, current);
482 sp_svgview_normal_cursor(ss);
483 }
485 static void
486 sp_svgview_goto_first (struct SPSlideShow *ss)
487 {
488 sp_svgview_waiting_cursor(ss);
490 SPDocument *doc = NULL;
491 int current = 0;
492 while ( !doc && (current < ss->length - 1)) {
493 if (current == ss->current)
494 break;
495 doc = SPDocument::createNewDoc (ss->slides[current++], TRUE, false);
496 }
498 sp_svgview_set_document(ss, doc, current - 1);
500 sp_svgview_normal_cursor(ss);
501 }
503 static void
504 sp_svgview_goto_last (struct SPSlideShow *ss)
505 {
506 sp_svgview_waiting_cursor(ss);
508 SPDocument *doc = NULL;
509 int current = ss->length - 1;
510 while (!doc && (current >= 0)) {
511 if (current == ss->current)
512 break;
513 doc = SPDocument::createNewDoc (ss->slides[current--], TRUE, false);
514 }
516 sp_svgview_set_document(ss, doc, current + 1);
518 sp_svgview_normal_cursor(ss);
519 }
521 #ifdef WITH_INKJAR
522 static bool
523 is_jar(char const *filename)
524 {
525 /* fixme: Check MIME type or something. /usr/share/misc/file/magic suggests that checking for
526 initial string "PK\003\004" in content should suffice. */
527 size_t const filename_len = strlen(filename);
528 if (filename_len < 5) {
529 return false;
530 }
531 char const *extension = filename + filename_len - 4;
532 return ((memcmp(extension, ".jar", 4) == 0) ||
533 (memcmp(extension, ".sxw", 4) == 0) );
534 }
535 #endif /* WITH_INKJAR */
537 static void usage()
538 {
539 fprintf(stderr,
540 "Usage: inkview [OPTIONS...] [FILES ...]\n"
541 "\twhere FILES are SVG (.svg or .svgz)"
542 #ifdef WITH_INKJAR
543 " or archives of SVGs (.sxw, .jar)"
544 #endif
545 "\n");
546 exit(1);
547 }
549 #ifdef XXX
550 /* TODO !!! make this temporary stub unnecessary */
551 Inkscape::Application *inkscape_get_instance() { return NULL; }
552 void inkscape_ref (void) {}
553 void inkscape_unref (void) {}
554 void inkscape_add_document (SPDocument *document) {}
555 void inkscape_remove_document (SPDocument *document) {}
556 #endif
559 /*
560 Local Variables:
561 mode:c++
562 c-file-style:"stroustrup"
563 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
564 indent-tabs-mode:nil
565 fill-column:99
566 End:
567 */
568 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :