Code

A simple layout document as to what, why and how is cppification.
[inkscape.git] / src / inkview.cpp
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 "io/inkjar.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     GtkWidget *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*/)
118     gtk_main_quit ();
119     return FALSE;
122 static int
123 sp_svgview_main_key_press (GtkWidget */*widget*/, GdkEventKey *event, struct SPSlideShow *ss)
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 (GTK_WINDOW(ss->window));
138             ss->fullscreen = false;
139         } else {
140             gtk_window_fullscreen (GTK_WINDOW(ss->window));
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(ss->window), SP_DOCUMENT_NAME(ss->doc));
171     return TRUE;
174 int
175 main (int argc, const char **argv)
177     if (argc == 1) {
178         usage();
179     }
181     // Prevents errors like "Unable to wrap GdkPixbuf..." (in nr-filter-image.cpp for example)
182     Gtk::Main::init_gtkmm_internals();
184     Gtk::Main main_instance (&argc, const_cast<char ***>(&argv));
186     struct SPSlideShow ss;
188     int option,
189         num_parsed_options = 0;
191     // the list of arguments is in the net line
192     while ((option = getopt(argc, (char* const* )argv, "t:")) != -1)
193     {
194         switch(option) {
195             case 't': // for timer
196                 // fprintf(stderr, "set timer arg %s\n", optarg );
197                 ss.timer = atoi(optarg);
198                 num_parsed_options += 2; // 2 because of flag + option
199                 break;
200             case '?':
201             default:
202                 usage();
203         }
204     }
206     GtkWidget *w;
207     int i;
209     bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
210     bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
211     textdomain (GETTEXT_PACKAGE);
213     LIBXML_TEST_VERSION
215     Inkscape::GC::init();
216     Inkscape::Preferences::get(); // ensure preferences are initialized
218     gtk_init (&argc, (char ***) &argv);
220 #ifdef lalaWITH_MODULES
221     g_warning ("Have to autoinit modules (lauris)");
222     sp_modulesys_init();
223 #endif /* WITH_MODULES */
225     /* We must set LC_NUMERIC to default, or otherwise */
226     /* we'll end with localised SVG files :-( */
228     setlocale (LC_NUMERIC, "C");
230     ss.size = 32;
231     ss.length = 0;
232     ss.current = 0;
233     ss.slides = g_new (char *, ss.size);
234     ss.current = 0;
235     ss.doc = NULL;
236     ss.view = NULL;
237     ss.fullscreen = false;
239     inkscape = (Inkscape::Application *)g_object_new (SP_TYPE_INKSCAPE, NULL);
241     // starting at where the commandline options stopped parsing because
242     // we want all the files to be in the list
243     for (i = num_parsed_options + 1 ; i < argc; i++) {
244         struct stat st;
245         if (stat (argv[i], &st)
246               || !S_ISREG (st.st_mode)
247               || (st.st_size < 64)) {
248                 fprintf(stderr, "could not open file %s\n", argv[i]);
249         } else {
251 #ifdef WITH_INKJAR
252             if (is_jar(argv[i])) {
253                 Inkjar::JarFileReader jar_file_reader(argv[i]);
254                 for (;;) {
255                     GByteArray *gba = jar_file_reader.get_next_file();
256                     if (gba == NULL) {
257                         char *c_ptr;
258                         gchar *last_filename = jar_file_reader.get_last_filename();
259                         if (last_filename == NULL)
260                             break;
261                         if ((c_ptr = std::strrchr(last_filename, '/')) != NULL) {
262                             if (*(++c_ptr) == '\0') {
263                                 g_free(last_filename);
264                                 continue;
265                             }
266                         }
267                     } else if (gba->len > 0) {
268                         //::write(1, gba->data, gba->len);
269                         /* Append to list */
270                         if (ss.length >= ss.size) {
271                             /* Expand */
272                             ss.size <<= 1;
273                             ss.slides = g_renew (char *, ss.slides, ss.size);
274                         }
276                         ss.doc = SPDocument::createNewDocFromMem ((const gchar *)gba->data,
277                                                            gba->len,
278                                                            TRUE);
279                         gchar *last_filename = jar_file_reader.get_last_filename();
280                         if (ss.doc) {
281                             ss.slides[ss.length++] = strdup (last_filename);
282                             (ss.doc)->setUri (strdup(last_filename));
283                         }
284                         g_byte_array_free(gba, TRUE);
285                         g_free(last_filename);
286                     } else
287                         break;
288                 }
289             } else {
290 #endif /* WITH_INKJAR */
291                 /* Append to list */
292                 if (ss.length >= ss.size) {
293                     /* Expand */
294                     ss.size <<= 1;
295                     ss.slides = g_renew (char *, ss.slides, ss.size);
297                 }
299                 ss.slides[ss.length++] = strdup (argv[i]);
301                 if (!ss.doc) {
302                     ss.doc = SPDocument::createNewDoc (ss.slides[ss.current], TRUE, false);
303                     if (!ss.doc)
304                         ++ss.current;
305                 }
306 #ifdef WITH_INKJAR
307             }
308 #endif
309         }
310     }
312     if(!ss.doc)
313        return 1; /* none of the slides loadable */
315     w = gtk_window_new (GTK_WINDOW_TOPLEVEL);
316     gtk_window_set_title (GTK_WINDOW (w), SP_DOCUMENT_NAME (ss.doc));
317     gtk_window_set_default_size (GTK_WINDOW (w),
318                                  MIN ((int)(ss.doc)->getWidth (), (int)gdk_screen_width () - 64),
319                                  MIN ((int)(ss.doc)->getHeight (), (int)gdk_screen_height () - 64));
320     gtk_window_set_policy (GTK_WINDOW (w), TRUE, TRUE, FALSE);
321     ss.window = w;
323     g_signal_connect (G_OBJECT (w), "delete_event", (GCallback) sp_svgview_main_delete, &ss);
324     g_signal_connect (G_OBJECT (w), "key_press_event", (GCallback) sp_svgview_main_key_press, &ss);
326     (ss.doc)->ensure_up_to_date ();
327     ss.view = sp_svg_view_widget_new (ss.doc);
328     (ss.doc)->doUnref ();
329     sp_svg_view_widget_set_resize (SP_SVG_VIEW_WIDGET (ss.view), FALSE,
330                                    (ss.doc)->getWidth (), (ss.doc)->getHeight ());
331     gtk_widget_show (ss.view);
332     gtk_container_add (GTK_CONTAINER (w), ss.view);
334     gtk_widget_show (w);
336     gtk_main ();
338     return 0;
341 static int
342 sp_svgview_ctrlwin_delete (GtkWidget */*widget*/, GdkEvent */*event*/, void */*data*/)
344     ctrlwin = NULL;
345     return FALSE;
348 static GtkWidget *
349 sp_svgview_control_show (struct SPSlideShow *ss)
351     if (!ctrlwin) {
352         GtkWidget *t, *b;
353         ctrlwin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
354     gtk_window_set_transient_for (GTK_WINDOW(ctrlwin), GTK_WINDOW(ss->window));
355     g_signal_connect (G_OBJECT (ctrlwin), "key_press_event", (GCallback) sp_svgview_main_key_press, ss);
356         g_signal_connect (G_OBJECT (ctrlwin), "delete_event", (GCallback) sp_svgview_ctrlwin_delete, NULL);
357         t = gtk_table_new (1, 4, TRUE);
358         gtk_container_add ((GtkContainer *) ctrlwin, t);
359         b = gtk_button_new_from_stock (GTK_STOCK_GOTO_FIRST);
360         gtk_table_attach ((GtkTable *) t, b, 0, 1, 0, 1,
361                           (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
362                           (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
363                           0, 0);
364         g_signal_connect ((GObject *) b, "clicked", (GCallback) sp_svgview_goto_first_cb, ss);
365         b = gtk_button_new_from_stock (GTK_STOCK_GO_BACK);
366         gtk_table_attach ((GtkTable *) t, b, 1, 2, 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_prev_cb, ss);
371         b = gtk_button_new_from_stock (GTK_STOCK_GO_FORWARD);
372         gtk_table_attach ((GtkTable *) t, b, 2, 3, 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_show_next_cb, ss);
377         b = gtk_button_new_from_stock (GTK_STOCK_GOTO_LAST);
378         gtk_table_attach ((GtkTable *) t, b, 3, 4, 0, 1,
379                           (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
380                           (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
381                           0, 0);
382         g_signal_connect (G_OBJECT(b), "clicked", (GCallback) sp_svgview_goto_last_cb, ss);
383         gtk_widget_show_all (ctrlwin);
384     } else {
385         gtk_window_present ((GtkWindow *) ctrlwin);
386     }
388     return NULL;
391 static int
392 sp_svgview_show_next_cb (GtkWidget */*widget*/, void *data)
394     sp_svgview_show_next(static_cast<struct SPSlideShow *>(data));
395     return FALSE;
398 static int
399 sp_svgview_show_prev_cb (GtkWidget */*widget*/, void *data)
401     sp_svgview_show_prev(static_cast<struct SPSlideShow *>(data));
402     return FALSE;
405 static int
406 sp_svgview_goto_first_cb (GtkWidget */*widget*/, void *data)
408     sp_svgview_goto_first(static_cast<struct SPSlideShow *>(data));
409     return FALSE;
412 static int
413 sp_svgview_goto_last_cb (GtkWidget */*widget*/, void *data)
415     sp_svgview_goto_last(static_cast<struct SPSlideShow *>(data));
416     return FALSE;
419 static void
420 sp_svgview_waiting_cursor(struct SPSlideShow *ss)
422     GdkCursor *waiting = gdk_cursor_new(GDK_WATCH);
423     gdk_window_set_cursor(GTK_WIDGET(ss->window)->window, waiting);
424     gdk_cursor_unref(waiting);
425     if (ctrlwin) {
426         GdkCursor *waiting = gdk_cursor_new(GDK_WATCH);
427         gdk_window_set_cursor(GTK_WIDGET(ctrlwin)->window, waiting);
428         gdk_cursor_unref(waiting);
429     }
430     while(gtk_events_pending())
431        gtk_main_iteration();
434 static void
435 sp_svgview_normal_cursor(struct SPSlideShow *ss)
437    gdk_window_set_cursor(GTK_WIDGET(ss->window)->window, NULL);
438     if (ctrlwin) {
439         gdk_window_set_cursor(GTK_WIDGET(ctrlwin)->window, NULL);
440     }
443 static void
444 sp_svgview_set_document(struct SPSlideShow *ss, SPDocument *doc, int current)
446     if (doc && doc != ss->doc) {
447         doc->ensure_up_to_date ();
448         reinterpret_cast<SPSVGView*>(SP_VIEW_WIDGET_VIEW (ss->view))->setDocument (doc);
449         ss->doc = doc;
450         ss->current = current;
451     }
454 static void
455 sp_svgview_show_next (struct SPSlideShow *ss)
457     sp_svgview_waiting_cursor(ss);
459     SPDocument *doc = NULL;
460     int current = ss->current;
461     while (!doc && (current < ss->length - 1)) {
462         doc = SPDocument::createNewDoc (ss->slides[++current], TRUE, false);
463     }
465     sp_svgview_set_document(ss, doc, current);
467     sp_svgview_normal_cursor(ss);
470 static void
471 sp_svgview_show_prev (struct SPSlideShow *ss)
473     sp_svgview_waiting_cursor(ss);
475     SPDocument *doc = NULL;
476     int current = ss->current;
477     while (!doc && (current > 0)) {
478         doc = SPDocument::createNewDoc (ss->slides[--current], TRUE, false);
479     }
481     sp_svgview_set_document(ss, doc, current);
483     sp_svgview_normal_cursor(ss);
486 static void
487 sp_svgview_goto_first (struct SPSlideShow *ss)
489     sp_svgview_waiting_cursor(ss);
491     SPDocument *doc = NULL;
492     int current = 0;
493     while ( !doc && (current < ss->length - 1)) {
494         if (current == ss->current)
495             break;
496         doc = SPDocument::createNewDoc (ss->slides[current++], TRUE, false);
497     }
499     sp_svgview_set_document(ss, doc, current - 1);
501     sp_svgview_normal_cursor(ss);
504 static void
505 sp_svgview_goto_last (struct SPSlideShow *ss)
507     sp_svgview_waiting_cursor(ss);
509     SPDocument *doc = NULL;
510     int current = ss->length - 1;
511     while (!doc && (current >= 0)) {
512         if (current == ss->current)
513             break;
514         doc = SPDocument::createNewDoc (ss->slides[current--], TRUE, false);
515     }
517     sp_svgview_set_document(ss, doc, current + 1);
519     sp_svgview_normal_cursor(ss);
522 #ifdef WITH_INKJAR
523 static bool
524 is_jar(char const *filename)
526     /* fixme: Check MIME type or something.  /usr/share/misc/file/magic suggests that checking for
527        initial string "PK\003\004" in content should suffice. */
528     size_t const filename_len = strlen(filename);
529     if (filename_len < 5) {
530         return false;
531     }
532     char const *extension = filename + filename_len - 4;
533     return ((memcmp(extension, ".jar", 4) == 0) ||
534             (memcmp(extension, ".sxw", 4) == 0)   );
536 #endif /* WITH_INKJAR */
538 static void usage()
540     fprintf(stderr,
541             "Usage: inkview [OPTIONS...] [FILES ...]\n"
542             "\twhere FILES are SVG (.svg or .svgz)"
543 #ifdef WITH_INKJAR
544             " or archives of SVGs (.sxw, .jar)"
545 #endif
546             "\n");
547     exit(1);
550 #ifdef XXX
551 /* TODO !!! make this temporary stub unnecessary */
552 Inkscape::Application *inkscape_get_instance() { return NULL; }
553 void inkscape_ref (void) {}
554 void inkscape_unref (void) {}
555 void inkscape_add_document (SPDocument *document) {}
556 void inkscape_remove_document (SPDocument *document) {}
557 #endif
560 /*
561   Local Variables:
562   mode:c++
563   c-file-style:"stroustrup"
564   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
565   indent-tabs-mode:nil
566   fill-column:99
567   End:
568 */
569 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :