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 <libnr/nr-macros.h>
40 #include <libxml/tree.h>
41 #include <gdk/gdkkeysyms.h>
42 #include <gtk/gtkmain.h>
43 #include <gtk/gtkstock.h>
44 #include <gtk/gtkwindow.h>
45 #include <gtk/gtktable.h>
46 #include <gtk/gtkbutton.h>
48 #include "gc-core.h"
49 #include "preferences.h"
51 #include <glibmm/i18n.h>
52 #include "document.h"
53 #include "svg-view.h"
54 #include "svg-view-widget.h"
56 #ifdef WITH_INKJAR
57 #include "inkjar/jar.h"
58 #endif
60 #include "inkscape-private.h"
62 Inkscape::Application *inkscape;
64 #include <iostream>
66 #ifndef HAVE_BIND_TEXTDOMAIN_CODESET
67 #define bind_textdomain_codeset(p,c)
68 #endif
70 struct SPSlideShow {
71 char **slides;
72 int size;
73 int length;
74 int current;
75 SPDocument *doc;
76 GtkWidget *view;
77 GtkWindow *window;
78 bool fullscreen;
79 };
81 static GtkWidget *sp_svgview_control_show (struct SPSlideShow *ss);
82 static void sp_svgview_show_next (struct SPSlideShow *ss);
83 static void sp_svgview_show_prev (struct SPSlideShow *ss);
84 static void sp_svgview_goto_first (struct SPSlideShow *ss);
85 static void sp_svgview_goto_last (struct SPSlideShow *ss);
87 static int sp_svgview_show_next_cb (GtkWidget *widget, void *data);
88 static int sp_svgview_show_prev_cb (GtkWidget *widget, void *data);
89 static int sp_svgview_goto_first_cb (GtkWidget *widget, void *data);
90 static int sp_svgview_goto_last_cb (GtkWidget *widget, void *data);
91 #ifdef WITH_INKJAR
92 static bool is_jar(char const *filename);
93 #endif
94 static void usage();
96 static GtkWidget *ctrlwin = NULL;
98 /// Dummy functions to keep linker happy
99 int sp_main_gui (int, char const**) { return 0; }
100 int sp_main_console (int, char const**) { return 0; }
102 static int
103 sp_svgview_main_delete (GtkWidget *widget, GdkEvent *event, struct SPSlideShow *ss)
104 {
105 gtk_main_quit ();
106 return FALSE;
107 }
109 static int
110 sp_svgview_main_key_press (GtkWidget *widget, GdkEventKey *event, struct SPSlideShow *ss)
111 {
112 switch (event->keyval) {
113 case GDK_Up:
114 sp_svgview_goto_first(ss);
115 break;
116 case GDK_Down:
117 sp_svgview_goto_last(ss);
118 break;
119 case GDK_F11:
120 #ifdef HAVE_GTK_WINDOW_FULLSCREEN
121 if (ss->fullscreen) {
122 gtk_window_unfullscreen ((GtkWindow *) widget);
123 ss->fullscreen = false;
124 } else {
125 gtk_window_fullscreen ((GtkWindow *) widget);
126 ss->fullscreen = true;
127 }
128 #else
129 std::cout<<"Your GTK+ does not support fullscreen mode. Upgrade to 2.2."<<std::endl;
130 #endif
131 break;
132 case GDK_Return:
133 sp_svgview_control_show (ss);
134 break;
135 case GDK_KP_Page_Down:
136 case GDK_Page_Down:
137 case GDK_Right:
138 case GDK_space:
139 sp_svgview_show_next (ss);
140 break;
141 case GDK_KP_Page_Up:
142 case GDK_Page_Up:
143 case GDK_Left:
144 sp_svgview_show_prev (ss);
145 break;
146 case GDK_Escape:
147 case GDK_q:
148 case GDK_Q:
149 gtk_main_quit();
150 break;
151 default:
152 break;
153 }
154 gtk_window_set_title(GTK_WINDOW(widget), SP_DOCUMENT_NAME(ss->doc));
155 return FALSE;
156 }
158 int
159 main (int argc, const char **argv)
160 {
161 if (argc == 1) {
162 usage();
163 }
165 struct SPSlideShow ss;
167 GtkWidget *w;
168 int i;
170 bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
171 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
172 textdomain (GETTEXT_PACKAGE);
174 LIBXML_TEST_VERSION
176 Inkscape::GC::init();
177 Inkscape::Preferences::loadSkeleton();
179 gtk_init (&argc, (char ***) &argv);
181 #ifdef lalaWITH_MODULES
182 g_warning ("Have to autoinit modules (lauris)");
183 sp_modulesys_init();
184 #endif /* WITH_MODULES */
186 /* We must set LC_NUMERIC to default, or otherwise */
187 /* we'll end with localised SVG files :-( */
189 setlocale (LC_NUMERIC, "C");
191 ss.size = 32;
192 ss.length = 0;
193 ss.current = 0;
194 ss.slides = nr_new (char *, ss.size);
195 ss.current = 0;
196 ss.doc = NULL;
197 ss.view = NULL;
198 ss.fullscreen = false;
200 inkscape = (Inkscape::Application *)g_object_new (SP_TYPE_INKSCAPE, NULL);
201 Inkscape::Preferences::load();
203 for (i = 1; i < argc; i++) {
204 struct stat st;
205 if (stat (argv[i], &st)
206 || !S_ISREG (st.st_mode)
207 || (st.st_size < 64)) {
208 fprintf(stderr, "could not open file %s\n", argv[i]);
209 } else {
211 #ifdef WITH_INKJAR
212 if (is_jar(argv[i])) {
213 Inkjar::JarFileReader jar_file_reader(argv[i]);
214 for (;;) {
215 GByteArray *gba = jar_file_reader.get_next_file();
216 if (gba == NULL) {
217 char *c_ptr;
218 gchar *last_filename = jar_file_reader.get_last_filename();
219 if (last_filename == NULL)
220 break;
221 if ((c_ptr = std::strrchr(last_filename, '/')) != NULL) {
222 if (*(++c_ptr) == '\0') {
223 g_free(last_filename);
224 continue;
225 }
226 }
227 } else if (gba->len > 0) {
228 //::write(1, gba->data, gba->len);
229 /* Append to list */
230 if (ss.length >= ss.size) {
231 /* Expand */
232 ss.size <<= 1;
233 ss.slides = nr_renew (ss.slides, char *, ss.size);
234 }
236 ss.doc = sp_document_new_from_mem ((const gchar *)gba->data,
237 gba->len,
238 TRUE);
239 gchar *last_filename = jar_file_reader.get_last_filename();
240 if (ss.doc) {
241 ss.slides[ss.length++] = strdup (last_filename);
242 sp_document_set_uri (ss.doc, strdup(last_filename));
243 }
244 g_byte_array_free(gba, TRUE);
245 g_free(last_filename);
246 } else
247 break;
248 }
249 } else {
250 #endif /* WITH_INKJAR */
251 /* Append to list */
252 if (ss.length >= ss.size) {
253 /* Expand */
254 ss.size <<= 1;
255 ss.slides = nr_renew (ss.slides, char *, ss.size);
257 }
259 ss.slides[ss.length++] = strdup (argv[i]);
260 ss.doc = sp_document_new (ss.slides[ss.current], TRUE, false);
262 if (!ss.doc && ++ss.current >= ss.length) {
263 /* No loadable documents */
264 return 1;
265 }
266 #ifdef WITH_INKJAR
267 }
268 #endif
269 }
270 }
272 if(!ss.doc)
273 return 1; /* none of the slides loadable */
275 w = gtk_window_new (GTK_WINDOW_TOPLEVEL);
276 gtk_window_set_title (GTK_WINDOW (w), SP_DOCUMENT_NAME (ss.doc));
277 gtk_window_set_default_size (GTK_WINDOW (w),
278 MIN ((int)sp_document_width (ss.doc), (int)gdk_screen_width () - 64),
279 MIN ((int)sp_document_height (ss.doc), (int)gdk_screen_height () - 64));
280 gtk_window_set_policy (GTK_WINDOW (w), TRUE, TRUE, FALSE);
282 g_signal_connect (G_OBJECT (w), "delete_event", (GCallback) sp_svgview_main_delete, &ss);
283 g_signal_connect (G_OBJECT (w), "key_press_event", (GCallback) sp_svgview_main_key_press, &ss);
285 ss.view = sp_svg_view_widget_new (ss.doc);
286 sp_svg_view_widget_set_resize (SP_SVG_VIEW_WIDGET (ss.view), FALSE, sp_document_width (ss.doc), sp_document_height (ss.doc));
287 sp_document_ensure_up_to_date (ss.doc);
288 sp_document_unref (ss.doc);
289 gtk_widget_show (ss.view);
290 gtk_container_add (GTK_CONTAINER (w), ss.view);
292 gtk_widget_show (w);
294 gtk_main ();
296 return 0;
297 }
299 static int
300 sp_svgview_ctrlwin_delete (GtkWidget *widget, GdkEvent *event, void *data)
301 {
302 ctrlwin = NULL;
303 return FALSE;
304 }
306 static GtkWidget *
307 sp_svgview_control_show (struct SPSlideShow *ss)
308 {
309 if (!ctrlwin) {
310 GtkWidget *t, *b;
311 ctrlwin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
312 g_signal_connect (G_OBJECT (ctrlwin), "delete_event", (GCallback) sp_svgview_ctrlwin_delete, NULL);
313 t = gtk_table_new (1, 4, TRUE);
314 gtk_container_add ((GtkContainer *) ctrlwin, t);
315 b = gtk_button_new_from_stock (GTK_STOCK_GOTO_FIRST);
316 gtk_table_attach ((GtkTable *) t, b, 0, 1, 0, 1,
317 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
318 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
319 0, 0);
320 g_signal_connect ((GObject *) b, "clicked", (GCallback) sp_svgview_goto_first_cb, ss);
321 b = gtk_button_new_from_stock (GTK_STOCK_GO_BACK);
322 gtk_table_attach ((GtkTable *) t, b, 1, 2, 0, 1,
323 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
324 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
325 0, 0);
326 g_signal_connect (G_OBJECT(b), "clicked", (GCallback) sp_svgview_show_prev_cb, ss);
327 b = gtk_button_new_from_stock (GTK_STOCK_GO_FORWARD);
328 gtk_table_attach ((GtkTable *) t, b, 2, 3, 0, 1,
329 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
330 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
331 0, 0);
332 g_signal_connect (G_OBJECT(b), "clicked", (GCallback) sp_svgview_show_next_cb, ss);
333 b = gtk_button_new_from_stock (GTK_STOCK_GOTO_LAST);
334 gtk_table_attach ((GtkTable *) t, b, 3, 4, 0, 1,
335 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
336 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
337 0, 0);
338 g_signal_connect (G_OBJECT(b), "clicked", (GCallback) sp_svgview_goto_last_cb, ss);
339 gtk_widget_show_all (ctrlwin);
340 } else {
341 gtk_window_present ((GtkWindow *) ctrlwin);
342 }
344 return NULL;
345 }
347 static int
348 sp_svgview_show_next_cb (GtkWidget *widget, void *data)
349 {
350 sp_svgview_show_next(static_cast<struct SPSlideShow *>(data));
351 return FALSE;
352 }
354 static int
355 sp_svgview_show_prev_cb (GtkWidget *widget, void *data)
356 {
357 sp_svgview_show_prev(static_cast<struct SPSlideShow *>(data));
358 return FALSE;
359 }
361 static int
362 sp_svgview_goto_first_cb (GtkWidget *widget, void *data)
363 {
364 sp_svgview_goto_first(static_cast<struct SPSlideShow *>(data));
365 return FALSE;
366 }
368 static int
369 sp_svgview_goto_last_cb (GtkWidget *widget, void *data)
370 {
371 sp_svgview_goto_last(static_cast<struct SPSlideShow *>(data));
372 return FALSE;
373 }
375 static void
376 sp_svgview_show_next (struct SPSlideShow *ss)
377 {
378 SPDocument *doc;
379 int current;
380 doc = NULL;
381 current = ss->current;
382 while (!doc && (current < ss->length - 1)) {
383 doc = sp_document_new (ss->slides[++current], TRUE, false);
384 }
385 if (doc) {
386 reinterpret_cast<SPSVGView*>(SP_VIEW_WIDGET_VIEW (ss->view))->setDocument (doc);
387 sp_document_ensure_up_to_date (doc);
388 ss->doc = doc;
389 ss->current = current;
390 }
391 }
393 static void
394 sp_svgview_show_prev (struct SPSlideShow *ss)
395 {
396 SPDocument *doc;
397 int current;
398 doc = NULL;
399 current = ss->current;
400 while (!doc && (current > 0)) {
401 doc = sp_document_new (ss->slides[--current], TRUE, false);
402 }
403 if (doc) {
404 reinterpret_cast<SPSVGView*>(SP_VIEW_WIDGET_VIEW (ss->view))->setDocument (doc);
405 sp_document_ensure_up_to_date (doc);
406 ss->doc = doc;
407 ss->current = current;
408 }
409 }
411 static void
412 sp_svgview_goto_first (struct SPSlideShow *ss)
413 {
414 SPDocument *doc = NULL;
415 int current = 0;
416 for ( ; !doc && (current < ss->length); current++) {
417 doc = sp_document_new (ss->slides[current], TRUE, false);
418 }
419 if (doc) {
420 reinterpret_cast<SPSVGView*>(SP_VIEW_WIDGET_VIEW (ss->view))->setDocument (doc);
421 sp_document_ensure_up_to_date (doc);
422 ss->doc = doc;
423 ss->current = current;
424 }
425 }
427 static void
428 sp_svgview_goto_last (struct SPSlideShow *ss)
429 {
430 SPDocument *doc = NULL;
431 int current = ss->length - 1;
432 for ( ; !doc && (current >= 0); current--) {
433 doc = sp_document_new (ss->slides[current], TRUE, false);
434 }
435 if (doc) {
436 reinterpret_cast<SPSVGView*>(SP_VIEW_WIDGET_VIEW (ss->view))->setDocument (doc);
437 sp_document_ensure_up_to_date (doc);
438 ss->doc = doc;
439 ss->current = current;
440 }
441 }
443 #ifdef WITH_INKJAR
444 static bool
445 is_jar(char const *filename)
446 {
447 /* fixme: Check MIME type or something. /usr/share/misc/file/magic suggests that checking for
448 initial string "PK\003\004" in content should suffice. */
449 size_t const filename_len = strlen(filename);
450 if (filename_len < 5) {
451 return false;
452 }
453 char const *extension = filename + filename_len - 4;
454 return ((memcmp(extension, ".jar", 4) == 0) ||
455 (memcmp(extension, ".sxw", 4) == 0) );
456 }
457 #endif /* WITH_INKJAR */
459 static void usage()
460 {
461 fprintf(stderr,
462 "Usage: inkview [FILES ...]\n"
463 "\twhere FILES are SVG (.svg or .svgz)"
464 #ifdef WITH_INKJAR
465 "or archives of SVGs (.sxw, .jar)"
466 #endif
467 "\n");
468 exit(1);
469 }
471 #ifdef XXX
472 /* TODO !!! make this temporary stub unnecessary */
473 Inkscape::Application *inkscape_get_instance() { return NULL; }
474 void inkscape_ref (void) {}
475 void inkscape_unref (void) {}
476 void inkscape_add_document (SPDocument *document) {}
477 void inkscape_remove_document (SPDocument *document) {}
478 Inkscape::XML::Node *inkscape_get_repr (Inkscape::Application *inkscape, const gchar *key) {return NULL;}
479 #endif
482 /*
483 Local Variables:
484 mode:c++
485 c-file-style:"stroustrup"
486 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
487 indent-tabs-mode:nil
488 fill-column:99
489 End:
490 */
491 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :