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 #ifdef HAVE_GETOPT_H
35 #include <getopt.h>
36 #endif
38 #include <string.h>
39 #include <sys/stat.h>
40 #include <locale.h>
42 #include <glib/gmem.h>
43 #include <libnr/nr-macros.h>
45 // #include <stropts.h>
47 #include <libxml/tree.h>
48 #include <gdk/gdkkeysyms.h>
49 #include <gtk/gtkmain.h>
50 #include <gtk/gtkstock.h>
51 #include <gtk/gtkwindow.h>
52 #include <gtk/gtktable.h>
53 #include <gtk/gtkbutton.h>
55 #include <gtkmm/main.h>
57 #include "gc-core.h"
58 #include "preferences.h"
60 #include <glibmm/i18n.h>
61 #include "document.h"
62 #include "svg-view.h"
63 #include "svg-view-widget.h"
65 #ifdef WITH_INKJAR
66 #include "inkjar/jar.h"
67 #endif
69 #include "inkscape-private.h"
71 Inkscape::Application *inkscape;
73 #include <iostream>
75 #ifndef HAVE_BIND_TEXTDOMAIN_CODESET
76 #define bind_textdomain_codeset(p,c)
77 #endif
79 extern char *optarg;
80 extern int optind, opterr;
82 struct SPSlideShow {
83 char **slides;
84 int size;
85 int length;
86 int current;
87 SPDocument *doc;
88 GtkWidget *view;
89 GtkWindow *window;
90 bool fullscreen;
91 int timer;
92 };
94 static GtkWidget *sp_svgview_control_show (struct SPSlideShow *ss);
95 static void sp_svgview_show_next (struct SPSlideShow *ss);
96 static void sp_svgview_show_prev (struct SPSlideShow *ss);
97 static void sp_svgview_goto_first (struct SPSlideShow *ss);
98 static void sp_svgview_goto_last (struct SPSlideShow *ss);
100 static int sp_svgview_show_next_cb (GtkWidget *widget, void *data);
101 static int sp_svgview_show_prev_cb (GtkWidget *widget, void *data);
102 static int sp_svgview_goto_first_cb (GtkWidget *widget, void *data);
103 static int sp_svgview_goto_last_cb (GtkWidget *widget, void *data);
104 #ifdef WITH_INKJAR
105 static bool is_jar(char const *filename);
106 #endif
107 static void usage();
109 static GtkWidget *ctrlwin = NULL;
111 /// Dummy functions to keep linker happy
112 int sp_main_gui (int, char const**) { return 0; }
113 int sp_main_console (int, char const**) { return 0; }
115 static int
116 sp_svgview_main_delete (GtkWidget *widget, GdkEvent *event, struct SPSlideShow *ss)
117 {
118 gtk_main_quit ();
119 return FALSE;
120 }
122 static int
123 sp_svgview_main_key_press (GtkWidget *widget, GdkEventKey *event, struct SPSlideShow *ss)
124 {
125 switch (event->keyval) {
126 case GDK_Up:
127 case GDK_Home:
128 sp_svgview_goto_first(ss);
129 break;
130 case GDK_Down:
131 case GDK_End:
132 sp_svgview_goto_last(ss);
133 break;
134 case GDK_F11:
135 #ifdef HAVE_GTK_WINDOW_FULLSCREEN
136 if (ss->fullscreen) {
137 gtk_window_unfullscreen ((GtkWindow *) widget);
138 ss->fullscreen = false;
139 } else {
140 gtk_window_fullscreen ((GtkWindow *) widget);
141 ss->fullscreen = true;
142 }
143 #else
144 std::cout<<"Your GTK+ does not support fullscreen mode. Upgrade to 2.2."<<std::endl;
145 #endif
146 break;
147 case GDK_Return:
148 sp_svgview_control_show (ss);
149 break;
150 case GDK_KP_Page_Down:
151 case GDK_Page_Down:
152 case GDK_Right:
153 case GDK_space:
154 sp_svgview_show_next (ss);
155 break;
156 case GDK_KP_Page_Up:
157 case GDK_Page_Up:
158 case GDK_Left:
159 case GDK_BackSpace:
160 sp_svgview_show_prev (ss);
161 break;
162 case GDK_Escape:
163 case GDK_q:
164 case GDK_Q:
165 gtk_main_quit();
166 break;
167 default:
168 break;
169 }
170 gtk_window_set_title(GTK_WINDOW(widget), SP_DOCUMENT_NAME(ss->doc));
171 return FALSE;
172 }
174 int
175 main (int argc, const char **argv)
176 {
177 if (argc == 1) {
178 usage();
179 }
181 Gtk::Main main_instance (&argc, const_cast<char ***>(&argv));
183 struct SPSlideShow ss;
185 int option,
186 num_parsed_options = 0;
188 // the list of arguments is in the net line
189 while ((option = getopt(argc, (char* const* )argv, "t:")) != -1)
190 {
191 switch(option) {
192 case 't': // for timer
193 // fprintf(stderr, "set timer arg %s\n", optarg );
194 ss.timer = atoi(optarg);
195 num_parsed_options += 2; // 2 because of flag + option
196 break;
197 case '?':
198 default:
199 usage();
200 }
201 }
203 GtkWidget *w;
204 int i;
206 bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
207 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
208 textdomain (GETTEXT_PACKAGE);
210 LIBXML_TEST_VERSION
212 Inkscape::GC::init();
213 Inkscape::Preferences::loadSkeleton();
215 gtk_init (&argc, (char ***) &argv);
217 #ifdef lalaWITH_MODULES
218 g_warning ("Have to autoinit modules (lauris)");
219 sp_modulesys_init();
220 #endif /* WITH_MODULES */
222 /* We must set LC_NUMERIC to default, or otherwise */
223 /* we'll end with localised SVG files :-( */
225 setlocale (LC_NUMERIC, "C");
227 ss.size = 32;
228 ss.length = 0;
229 ss.current = 0;
230 ss.slides = g_new (char *, ss.size);
231 ss.current = 0;
232 ss.doc = NULL;
233 ss.view = NULL;
234 ss.fullscreen = false;
236 inkscape = (Inkscape::Application *)g_object_new (SP_TYPE_INKSCAPE, NULL);
237 Inkscape::Preferences::load();
239 // starting at where the commandline options stopped parsing because
240 // we want all the files to be in the list
241 for (i = num_parsed_options + 1 ; i < argc; i++) {
242 struct stat st;
243 if (stat (argv[i], &st)
244 || !S_ISREG (st.st_mode)
245 || (st.st_size < 64)) {
246 fprintf(stderr, "could not open file %s\n", argv[i]);
247 } else {
249 #ifdef WITH_INKJAR
250 if (is_jar(argv[i])) {
251 Inkjar::JarFileReader jar_file_reader(argv[i]);
252 for (;;) {
253 GByteArray *gba = jar_file_reader.get_next_file();
254 if (gba == NULL) {
255 char *c_ptr;
256 gchar *last_filename = jar_file_reader.get_last_filename();
257 if (last_filename == NULL)
258 break;
259 if ((c_ptr = std::strrchr(last_filename, '/')) != NULL) {
260 if (*(++c_ptr) == '\0') {
261 g_free(last_filename);
262 continue;
263 }
264 }
265 } else if (gba->len > 0) {
266 //::write(1, gba->data, gba->len);
267 /* Append to list */
268 if (ss.length >= ss.size) {
269 /* Expand */
270 ss.size <<= 1;
271 ss.slides = g_renew (char *, ss.slides, ss.size);
272 }
274 ss.doc = sp_document_new_from_mem ((const gchar *)gba->data,
275 gba->len,
276 TRUE);
277 gchar *last_filename = jar_file_reader.get_last_filename();
278 if (ss.doc) {
279 ss.slides[ss.length++] = strdup (last_filename);
280 sp_document_set_uri (ss.doc, strdup(last_filename));
281 }
282 g_byte_array_free(gba, TRUE);
283 g_free(last_filename);
284 } else
285 break;
286 }
287 } else {
288 #endif /* WITH_INKJAR */
289 /* Append to list */
290 if (ss.length >= ss.size) {
291 /* Expand */
292 ss.size <<= 1;
293 ss.slides = g_renew (char *, ss.slides, ss.size);
295 }
297 ss.slides[ss.length++] = strdup (argv[i]);
298 ss.doc = sp_document_new (ss.slides[ss.current], TRUE, false);
300 if (!ss.doc && ++ss.current >= ss.length) {
301 /* No loadable documents */
302 return 1;
303 }
304 #ifdef WITH_INKJAR
305 }
306 #endif
307 }
308 }
310 if(!ss.doc)
311 return 1; /* none of the slides loadable */
313 w = gtk_window_new (GTK_WINDOW_TOPLEVEL);
314 gtk_window_set_title (GTK_WINDOW (w), SP_DOCUMENT_NAME (ss.doc));
315 gtk_window_set_default_size (GTK_WINDOW (w),
316 MIN ((int)sp_document_width (ss.doc), (int)gdk_screen_width () - 64),
317 MIN ((int)sp_document_height (ss.doc), (int)gdk_screen_height () - 64));
318 gtk_window_set_policy (GTK_WINDOW (w), TRUE, TRUE, FALSE);
320 g_signal_connect (G_OBJECT (w), "delete_event", (GCallback) sp_svgview_main_delete, &ss);
321 g_signal_connect (G_OBJECT (w), "key_press_event", (GCallback) sp_svgview_main_key_press, &ss);
323 ss.view = sp_svg_view_widget_new (ss.doc);
324 sp_svg_view_widget_set_resize (SP_SVG_VIEW_WIDGET (ss.view), FALSE, sp_document_width (ss.doc), sp_document_height (ss.doc));
325 sp_document_ensure_up_to_date (ss.doc);
326 sp_document_unref (ss.doc);
327 gtk_widget_show (ss.view);
328 gtk_container_add (GTK_CONTAINER (w), ss.view);
330 gtk_widget_show (w);
332 gtk_main ();
334 return 0;
335 }
337 static int
338 sp_svgview_ctrlwin_delete (GtkWidget *widget, GdkEvent *event, void *data)
339 {
340 ctrlwin = NULL;
341 return FALSE;
342 }
344 static GtkWidget *
345 sp_svgview_control_show (struct SPSlideShow *ss)
346 {
347 if (!ctrlwin) {
348 GtkWidget *t, *b;
349 ctrlwin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
350 g_signal_connect (G_OBJECT (ctrlwin), "delete_event", (GCallback) sp_svgview_ctrlwin_delete, NULL);
351 t = gtk_table_new (1, 4, TRUE);
352 gtk_container_add ((GtkContainer *) ctrlwin, t);
353 b = gtk_button_new_from_stock (GTK_STOCK_GOTO_FIRST);
354 gtk_table_attach ((GtkTable *) t, b, 0, 1, 0, 1,
355 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
356 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
357 0, 0);
358 g_signal_connect ((GObject *) b, "clicked", (GCallback) sp_svgview_goto_first_cb, ss);
359 b = gtk_button_new_from_stock (GTK_STOCK_GO_BACK);
360 gtk_table_attach ((GtkTable *) t, b, 1, 2, 0, 1,
361 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
362 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
363 0, 0);
364 g_signal_connect (G_OBJECT(b), "clicked", (GCallback) sp_svgview_show_prev_cb, ss);
365 b = gtk_button_new_from_stock (GTK_STOCK_GO_FORWARD);
366 gtk_table_attach ((GtkTable *) t, b, 2, 3, 0, 1,
367 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
368 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
369 0, 0);
370 g_signal_connect (G_OBJECT(b), "clicked", (GCallback) sp_svgview_show_next_cb, ss);
371 b = gtk_button_new_from_stock (GTK_STOCK_GOTO_LAST);
372 gtk_table_attach ((GtkTable *) t, b, 3, 4, 0, 1,
373 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
374 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
375 0, 0);
376 g_signal_connect (G_OBJECT(b), "clicked", (GCallback) sp_svgview_goto_last_cb, ss);
377 gtk_widget_show_all (ctrlwin);
378 } else {
379 gtk_window_present ((GtkWindow *) ctrlwin);
380 }
382 return NULL;
383 }
385 static int
386 sp_svgview_show_next_cb (GtkWidget *widget, void *data)
387 {
388 sp_svgview_show_next(static_cast<struct SPSlideShow *>(data));
389 return FALSE;
390 }
392 static int
393 sp_svgview_show_prev_cb (GtkWidget *widget, void *data)
394 {
395 sp_svgview_show_prev(static_cast<struct SPSlideShow *>(data));
396 return FALSE;
397 }
399 static int
400 sp_svgview_goto_first_cb (GtkWidget *widget, void *data)
401 {
402 sp_svgview_goto_first(static_cast<struct SPSlideShow *>(data));
403 return FALSE;
404 }
406 static int
407 sp_svgview_goto_last_cb (GtkWidget *widget, void *data)
408 {
409 sp_svgview_goto_last(static_cast<struct SPSlideShow *>(data));
410 return FALSE;
411 }
413 static void
414 sp_svgview_show_next (struct SPSlideShow *ss)
415 {
416 SPDocument *doc;
417 int current;
418 doc = NULL;
419 current = ss->current;
420 while (!doc && (current < ss->length - 1)) {
421 doc = sp_document_new (ss->slides[++current], TRUE, false);
422 }
423 if (doc) {
424 reinterpret_cast<SPSVGView*>(SP_VIEW_WIDGET_VIEW (ss->view))->setDocument (doc);
425 sp_document_ensure_up_to_date (doc);
426 ss->doc = doc;
427 ss->current = current;
428 }
429 }
431 static void
432 sp_svgview_show_prev (struct SPSlideShow *ss)
433 {
434 SPDocument *doc;
435 int current;
436 doc = NULL;
437 current = ss->current;
438 while (!doc && (current > 0)) {
439 doc = sp_document_new (ss->slides[--current], TRUE, false);
440 }
441 if (doc) {
442 reinterpret_cast<SPSVGView*>(SP_VIEW_WIDGET_VIEW (ss->view))->setDocument (doc);
443 sp_document_ensure_up_to_date (doc);
444 ss->doc = doc;
445 ss->current = current;
446 }
447 }
449 static void
450 sp_svgview_goto_first (struct SPSlideShow *ss)
451 {
452 SPDocument *doc = NULL;
453 int current = 0;
454 for ( ; !doc && (current < ss->length); current++) {
455 doc = sp_document_new (ss->slides[current], TRUE, false);
456 }
457 if (doc) {
458 reinterpret_cast<SPSVGView*>(SP_VIEW_WIDGET_VIEW (ss->view))->setDocument (doc);
459 sp_document_ensure_up_to_date (doc);
460 ss->doc = doc;
461 ss->current = current;
462 }
463 }
465 static void
466 sp_svgview_goto_last (struct SPSlideShow *ss)
467 {
468 SPDocument *doc = NULL;
469 int current = ss->length - 1;
470 for ( ; !doc && (current >= 0); current--) {
471 doc = sp_document_new (ss->slides[current], TRUE, false);
472 }
473 if (doc) {
474 reinterpret_cast<SPSVGView*>(SP_VIEW_WIDGET_VIEW (ss->view))->setDocument (doc);
475 sp_document_ensure_up_to_date (doc);
476 ss->doc = doc;
477 ss->current = current;
478 }
479 }
481 #ifdef WITH_INKJAR
482 static bool
483 is_jar(char const *filename)
484 {
485 /* fixme: Check MIME type or something. /usr/share/misc/file/magic suggests that checking for
486 initial string "PK\003\004" in content should suffice. */
487 size_t const filename_len = strlen(filename);
488 if (filename_len < 5) {
489 return false;
490 }
491 char const *extension = filename + filename_len - 4;
492 return ((memcmp(extension, ".jar", 4) == 0) ||
493 (memcmp(extension, ".sxw", 4) == 0) );
494 }
495 #endif /* WITH_INKJAR */
497 static void usage()
498 {
499 fprintf(stderr,
500 "Usage: inkview [OPTIONS...] [FILES ...]\n"
501 "\twhere FILES are SVG (.svg or .svgz)"
502 #ifdef WITH_INKJAR
503 " or archives of SVGs (.sxw, .jar)"
504 #endif
505 "\n\n"
506 "Available options:\n"
507 "\t-t\t\tTimer for automatically changing slides in seconds.\n"
508 "\n");
509 exit(1);
510 }
512 #ifdef XXX
513 /* TODO !!! make this temporary stub unnecessary */
514 Inkscape::Application *inkscape_get_instance() { return NULL; }
515 void inkscape_ref (void) {}
516 void inkscape_unref (void) {}
517 void inkscape_add_document (SPDocument *document) {}
518 void inkscape_remove_document (SPDocument *document) {}
519 Inkscape::XML::Node *inkscape_get_repr (Inkscape::Application *inkscape, const gchar *key) {return NULL;}
520 #endif
523 /*
524 Local Variables:
525 mode:c++
526 c-file-style:"stroustrup"
527 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
528 indent-tabs-mode:nil
529 fill-column:99
530 End:
531 */
532 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :