Code

Several icon name fixes
[inkscape.git] / src / main.cpp
1 #define __MAIN_C__
3 /** \file
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  *   Bryce Harrington <bryce@bryceharrington.com>
17  * ... and various people who have worked with various projects
18  *
19  * Copyright (C) 1999-2004 authors
20  * Copyright (C) 2001-2002 Ximian, Inc.
21  *
22  * Released under GNU GPL, read the file 'COPYING' for more information
23  */
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29 #include "path-prefix.h"
31 #include <gtk/gtkmessagedialog.h>
33 #ifdef HAVE_IEEEFP_H
34 #include <ieeefp.h>
35 #endif
36 #include <cstring>
37 #include <string>
38 #include <locale.h>
39 #include <stdlib.h>
41 #include <popt.h>
42 #ifndef POPT_TABLEEND
43 #define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL }
44 #endif /* Not def: POPT_TABLEEND */
46 #include <libxml/tree.h>
47 #include <glib-object.h>
48 #include <gtk/gtk.h>
49 #include <gtk/gtkmain.h>
50 #include <gtk/gtksignal.h>
51 #include <gtk/gtkwindow.h>
52 #include <gtk/gtkbox.h>
54 #include "gc-core.h"
56 #include "macros.h"
57 #include "file.h"
58 #include "document.h"
59 #include "sp-object.h"
60 #include "interface.h"
61 #include "print.h"
62 #include "color.h"
63 #include "sp-item.h"
64 #include "sp-root.h"
65 #include "unit-constants.h"
67 #include "svg/svg.h"
68 #include "svg/svg-color.h"
69 #include "svg/stringstream.h"
71 #include "inkscape-private.h"
72 #include "inkscape-version.h"
74 #include "sp-namedview.h"
75 #include "sp-guide.h"
76 #include "sp-object-repr.h"
77 #include "xml/repr.h"
79 #include "io/sys.h"
81 #include "debug/logger.h"
82 #include "debug/log-display-config.h"
84 #include "helper/png-write.h"
85 #include "helper/geom.h"
87 #include <extension/extension.h>
88 #include <extension/system.h>
89 #include <extension/db.h>
90 #include <extension/output.h>
92 #ifdef WIN32
93 //#define REPLACEARGS_ANSI
94 //#define REPLACEARGS_DEBUG
96 #include "registrytool.h"
98 #include "extension/internal/win32.h"
99 using Inkscape::Extension::Internal::PrintWin32;
101 #endif // WIN32
103 #include "extension/init.h"
105 #include <glibmm/i18n.h>
106 #include <gtkmm/main.h>
108 #ifndef HAVE_BIND_TEXTDOMAIN_CODESET
109 #define bind_textdomain_codeset(p,c)
110 #endif
112 #include "application/application.h"
113 #include "main-cmdlineact.h"
114 #include "widgets/icon.h"
115 #include "ui/widget/panel.h"
118 #include <png.h>
119 #include <errno.h>
121 enum {
122     SP_ARG_NONE,
123     SP_ARG_NOGUI,
124     SP_ARG_GUI,
125     SP_ARG_FILE,
126     SP_ARG_PRINT,
127     SP_ARG_EXPORT_PNG,
128     SP_ARG_EXPORT_DPI,
129     SP_ARG_EXPORT_AREA,
130     SP_ARG_EXPORT_AREA_DRAWING,
131     SP_ARG_EXPORT_AREA_CANVAS,
132     SP_ARG_EXPORT_AREA_SNAP,
133     SP_ARG_EXPORT_WIDTH,
134     SP_ARG_EXPORT_HEIGHT,
135     SP_ARG_EXPORT_ID,
136     SP_ARG_EXPORT_ID_ONLY,
137     SP_ARG_EXPORT_USE_HINTS,
138     SP_ARG_EXPORT_BACKGROUND,
139     SP_ARG_EXPORT_BACKGROUND_OPACITY,
140     SP_ARG_EXPORT_SVG,
141     SP_ARG_EXPORT_PS,
142     SP_ARG_EXPORT_EPS,
143     SP_ARG_EXPORT_PDF,
144 #ifdef WIN32
145     SP_ARG_EXPORT_EMF,
146 #endif //WIN32
147     SP_ARG_EXPORT_TEXT_TO_PATH,
148     SP_ARG_EXPORT_IGNORE_FILTERS,
149     SP_ARG_EXTENSIONDIR,
150     SP_ARG_QUERY_X,
151     SP_ARG_QUERY_Y,
152     SP_ARG_QUERY_WIDTH,
153     SP_ARG_QUERY_HEIGHT,
154     SP_ARG_QUERY_ALL,
155     SP_ARG_QUERY_ID,
156     SP_ARG_SHELL,
157     SP_ARG_VERSION,
158     SP_ARG_VACUUM_DEFS,
159     SP_ARG_VERB_LIST,
160     SP_ARG_VERB,
161     SP_ARG_SELECT,
162     SP_ARG_LAST
163 };
165 int sp_main_gui(int argc, char const **argv);
166 int sp_main_console(int argc, char const **argv);
167 static void sp_do_export_png(SPDocument *doc);
168 static void do_export_ps_pdf(SPDocument* doc, gchar const* uri, char const *mime);
169 #ifdef WIN32
170 static void do_export_emf(SPDocument* doc, gchar const* uri, char const *mime);
171 #endif //WIN32
172 static void do_query_dimension (SPDocument *doc, bool extent, Geom::Dim2 const axis, const gchar *id);
173 static void do_query_all (SPDocument *doc);
174 static void do_query_all_recurse (SPObject *o);
176 static gchar *sp_global_printer = NULL;
177 static gchar *sp_export_png = NULL;
178 static gchar *sp_export_dpi = NULL;
179 static gchar *sp_export_area = NULL;
180 static gboolean sp_export_area_drawing = FALSE;
181 static gboolean sp_export_area_canvas = FALSE;
182 static gchar *sp_export_width = NULL;
183 static gchar *sp_export_height = NULL;
184 static gchar *sp_export_id = NULL;
185 static gchar *sp_export_background = NULL;
186 static gchar *sp_export_background_opacity = NULL;
187 static gboolean sp_export_area_snap = FALSE;
188 static gboolean sp_export_use_hints = FALSE;
189 static gboolean sp_export_id_only = FALSE;
190 static gchar *sp_export_svg = NULL;
191 static gchar *sp_export_ps = NULL;
192 static gchar *sp_export_eps = NULL;
193 static gchar *sp_export_pdf = NULL;
194 #ifdef WIN32
195 static gchar *sp_export_emf = NULL;
196 #endif //WIN32
197 static gboolean sp_export_text_to_path = FALSE;
198 static gboolean sp_export_ignore_filters = FALSE;
199 static gboolean sp_export_font = FALSE;
200 static gboolean sp_query_x = FALSE;
201 static gboolean sp_query_y = FALSE;
202 static gboolean sp_query_width = FALSE;
203 static gboolean sp_query_height = FALSE;
204 static gboolean sp_query_all = FALSE;
205 static gchar *sp_query_id = NULL;
206 static int sp_new_gui = FALSE;
207 static gboolean sp_shell = FALSE;
208 static gboolean sp_vacuum_defs = FALSE;
210 static gchar *sp_export_png_utf8 = NULL;
211 static gchar *sp_export_svg_utf8 = NULL;
212 static gchar *sp_global_printer_utf8 = NULL;
215 /**
216  *  Reset variables to default values.
217  */
218 static void resetCommandlineGlobals() {
219         sp_global_printer = NULL;
220         sp_export_png = NULL;
221         sp_export_dpi = NULL;
222         sp_export_area = NULL;
223         sp_export_area_drawing = FALSE;
224         sp_export_area_canvas = FALSE;
225         sp_export_width = NULL;
226         sp_export_height = NULL;
227         sp_export_id = NULL;
228         sp_export_background = NULL;
229         sp_export_background_opacity = NULL;
230         sp_export_area_snap = FALSE;
231         sp_export_use_hints = FALSE;
232         sp_export_id_only = FALSE;
233         sp_export_svg = NULL;
234         sp_export_ps = NULL;
235         sp_export_eps = NULL;
236         sp_export_pdf = NULL;
237 #ifdef WIN32
238         sp_export_emf = NULL;
239 #endif //WIN32
240         sp_export_text_to_path = FALSE;
241         sp_export_ignore_filters = FALSE;
242         sp_export_font = FALSE;
243         sp_query_x = FALSE;
244         sp_query_y = FALSE;
245         sp_query_width = FALSE;
246         sp_query_height = FALSE;
247         sp_query_all = FALSE;
248         sp_query_id = NULL;
249         sp_vacuum_defs = FALSE;
251         sp_export_png_utf8 = NULL;
252         sp_export_svg_utf8 = NULL;
253         sp_global_printer_utf8 = NULL;
256 #ifdef WIN32
257 static bool replaceArgs( int& argc, char**& argv );
258 #endif
259 static GSList *sp_process_args(poptContext ctx);
260 struct poptOption options[] = {
261     {"version", 'V',
262      POPT_ARG_NONE, NULL, SP_ARG_VERSION,
263      N_("Print the Inkscape version number"),
264      NULL},
266     {"without-gui", 'z',
267      POPT_ARG_NONE, NULL, SP_ARG_NOGUI,
268      N_("Do not use X server (only process files from console)"),
269      NULL},
271     {"with-gui", 'g',
272      POPT_ARG_NONE, NULL, SP_ARG_GUI,
273      N_("Try to use X server (even if $DISPLAY is not set)"),
274      NULL},
276     {"file", 'f',
277      POPT_ARG_STRING, NULL, SP_ARG_FILE,
278      N_("Open specified document(s) (option string may be excluded)"),
279      N_("FILENAME")},
281     {"print", 'p',
282      POPT_ARG_STRING, &sp_global_printer, SP_ARG_PRINT,
283      N_("Print document(s) to specified output file (use '| program' for pipe)"),
284      N_("FILENAME")},
286     {"export-png", 'e',
287      POPT_ARG_STRING, &sp_export_png, SP_ARG_EXPORT_PNG,
288      N_("Export document to a PNG file"),
289      N_("FILENAME")},
291     {"export-dpi", 'd',
292      POPT_ARG_STRING, &sp_export_dpi, SP_ARG_EXPORT_DPI,
293      N_("The resolution used for exporting SVG into bitmap (default 90)"),
294      N_("DPI")},
296     {"export-area", 'a',
297      POPT_ARG_STRING, &sp_export_area, SP_ARG_EXPORT_AREA,
298      N_("Exported area in SVG user units (default is the canvas; 0,0 is lower-left corner)"),
299      N_("x0:y0:x1:y1")},
301     {"export-area-drawing", 'D',
302      POPT_ARG_NONE, &sp_export_area_drawing, SP_ARG_EXPORT_AREA_DRAWING,
303      N_("Exported area is the entire drawing (not canvas)"),
304      NULL},
306     {"export-area-canvas", 'C',
307      POPT_ARG_NONE, &sp_export_area_canvas, SP_ARG_EXPORT_AREA_CANVAS,
308      N_("Exported area is the entire canvas"),
309      NULL},
311     {"export-area-snap", 0,
312      POPT_ARG_NONE, &sp_export_area_snap, SP_ARG_EXPORT_AREA_SNAP,
313      N_("Snap the bitmap export area outwards to the nearest integer values (in SVG user units)"),
314      NULL},
316     {"export-width", 'w',
317      POPT_ARG_STRING, &sp_export_width, SP_ARG_EXPORT_WIDTH,
318      N_("The width of exported bitmap in pixels (overrides export-dpi)"),
319      N_("WIDTH")},
321     {"export-height", 'h',
322      POPT_ARG_STRING, &sp_export_height, SP_ARG_EXPORT_HEIGHT,
323      N_("The height of exported bitmap in pixels (overrides export-dpi)"),
324      N_("HEIGHT")},
326     {"export-id", 'i',
327      POPT_ARG_STRING, &sp_export_id, SP_ARG_EXPORT_ID,
328      N_("The ID of the object to export"),
329      N_("ID")},
331     {"export-id-only", 'j',
332      POPT_ARG_NONE, &sp_export_id_only, SP_ARG_EXPORT_ID_ONLY,
333      // TRANSLATORS: this means: "Only export the object whose id is given in --export-id".
334      //  See "man inkscape" for details.
335      N_("Export just the object with export-id, hide all others (only with export-id)"),
336      NULL},
338     {"export-use-hints", 't',
339      POPT_ARG_NONE, &sp_export_use_hints, SP_ARG_EXPORT_USE_HINTS,
340      N_("Use stored filename and DPI hints when exporting (only with export-id)"),
341      NULL},
343     {"export-background", 'b',
344      POPT_ARG_STRING, &sp_export_background, SP_ARG_EXPORT_BACKGROUND,
345      N_("Background color of exported bitmap (any SVG-supported color string)"),
346      N_("COLOR")},
348     {"export-background-opacity", 'y',
349      POPT_ARG_STRING, &sp_export_background_opacity, SP_ARG_EXPORT_BACKGROUND_OPACITY,
350      N_("Background opacity of exported bitmap (either 0.0 to 1.0, or 1 to 255)"),
351      N_("VALUE")},
353     {"export-plain-svg", 'l',
354      POPT_ARG_STRING, &sp_export_svg, SP_ARG_EXPORT_SVG,
355      N_("Export document to plain SVG file (no sodipodi or inkscape namespaces)"),
356      N_("FILENAME")},
358     {"export-ps", 'P',
359      POPT_ARG_STRING, &sp_export_ps, SP_ARG_EXPORT_PS,
360      N_("Export document to a PS file"),
361      N_("FILENAME")},
363     {"export-eps", 'E',
364      POPT_ARG_STRING, &sp_export_eps, SP_ARG_EXPORT_EPS,
365      N_("Export document to an EPS file"),
366      N_("FILENAME")},
368     {"export-pdf", 'A',
369      POPT_ARG_STRING, &sp_export_pdf, SP_ARG_EXPORT_PDF,
370      N_("Export document to a PDF file"),
371      N_("FILENAME")},
373 #ifdef WIN32
374     {"export-emf", 'M',
375      POPT_ARG_STRING, &sp_export_emf, SP_ARG_EXPORT_EMF,
376      N_("Export document to an Enhanced Metafile (EMF) File"),
377      N_("FILENAME")},
378 #endif //WIN32
380     {"export-text-to-path", 'T',
381      POPT_ARG_NONE, &sp_export_text_to_path, SP_ARG_EXPORT_TEXT_TO_PATH,
382      N_("Convert text object to paths on export (PS, EPS, PDF)"),
383      NULL},
385     {"export-ignore-filters", 0,
386      POPT_ARG_NONE, &sp_export_ignore_filters, SP_ARG_EXPORT_IGNORE_FILTERS,
387      N_("Render filtered objects without filters, instead of rasterizing (PS, EPS, PDF)"),
388      NULL},
390     {"query-x", 'X',
391      POPT_ARG_NONE, &sp_query_x, SP_ARG_QUERY_X,
392      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
393      N_("Query the X coordinate of the drawing or, if specified, of the object with --query-id"),
394      NULL},
396     {"query-y", 'Y',
397      POPT_ARG_NONE, &sp_query_y, SP_ARG_QUERY_Y,
398      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
399      N_("Query the Y coordinate of the drawing or, if specified, of the object with --query-id"),
400      NULL},
402     {"query-width", 'W',
403      POPT_ARG_NONE, &sp_query_width, SP_ARG_QUERY_WIDTH,
404      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
405      N_("Query the width of the drawing or, if specified, of the object with --query-id"),
406      NULL},
408     {"query-height", 'H',
409      POPT_ARG_NONE, &sp_query_height, SP_ARG_QUERY_HEIGHT,
410      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
411      N_("Query the height of the drawing or, if specified, of the object with --query-id"),
412      NULL},
414     {"query-all", 'S',
415      POPT_ARG_NONE, &sp_query_all, SP_ARG_QUERY_ALL,
416      N_("List id,x,y,w,h for all objects"),
417      NULL},
419     {"query-id", 'I',
420      POPT_ARG_STRING, &sp_query_id, SP_ARG_QUERY_ID,
421      N_("The ID of the object whose dimensions are queried"),
422      N_("ID")},
424     {"extension-directory", 'x',
425      POPT_ARG_NONE, NULL, SP_ARG_EXTENSIONDIR,
426      // TRANSLATORS: this option makes Inkscape print the name (path) of the extension directory
427      N_("Print out the extension directory and exit"),
428      NULL},
430     {"vacuum-defs", 0,
431      POPT_ARG_NONE, &sp_vacuum_defs, SP_ARG_VACUUM_DEFS,
432      N_("Remove unused definitions from the defs section(s) of the document"),
433      NULL},
435     {"verb-list", 0,
436      POPT_ARG_NONE, NULL, SP_ARG_VERB_LIST,
437      N_("List the IDs of all the verbs in Inkscape"),
438      NULL},
440     {"verb", 0,
441      POPT_ARG_STRING, NULL, SP_ARG_VERB,
442      N_("Verb to call when Inkscape opens."),
443      N_("VERB-ID")},
445     {"select", 0,
446      POPT_ARG_STRING, NULL, SP_ARG_SELECT,
447      N_("Object ID to select when Inkscape opens."),
448      N_("OBJECT-ID")},
450     {"shell", 0,
451      POPT_ARG_NONE, &sp_shell, SP_ARG_SHELL,
452      N_("Start Inkscape in interative shell mode."),
453      NULL},
455     POPT_AUTOHELP POPT_TABLEEND
456 };
458 static bool needToRecodeParams = true;
459 gchar * blankParam = g_strdup("");
463 #ifdef WIN32
465 /**
466  * Return the directory of the .exe that is currently running
467  */
468 static Glib::ustring _win32_getExePath()
470     char exeName[MAX_PATH+1];
471     GetModuleFileName(NULL, exeName, MAX_PATH);
472     char *slashPos = strrchr(exeName, '\\');
473     if (slashPos)
474         *slashPos = '\0';
475     Glib::ustring s = exeName;
476     return s;
479 /**
480  * Set up the PATH and PYTHONPATH environment variables on
481  * win32
482  */
483 static int _win32_set_inkscape_env(const Glib::ustring &exePath)
486     char *oldenv = getenv("PATH");
487     Glib::ustring tmp = "PATH=";
488     tmp += exePath;
489     tmp += ";";
490     tmp += exePath;
491     tmp += "\\python;";
492     tmp += exePath;
493     tmp += "\\python\\Scripts;";  // for uniconv.cmd
494     tmp += exePath;
495     tmp += "\\perl";
496     if(oldenv != NULL) {
497         tmp += ";";
498         tmp += oldenv;
499     }
500     _putenv(tmp.c_str());
502     oldenv = getenv("PYTHONPATH");
503     tmp = "PYTHONPATH=";
504     tmp += exePath;
505     tmp += "\\python;";
506     tmp += exePath;
507     tmp += "\\python\\Lib;";
508     tmp += exePath;
509     tmp += "\\python\\DLLs";
510     if(oldenv != NULL) {
511         tmp += ";";
512         tmp += oldenv;
513     }
514     _putenv(tmp.c_str());
516     return 0;
518 #endif
520 /**
521  * Add INKSCAPE_EXTENSIONDIR to PYTHONPATH so that extensions in users home
522  * can find inkex.py et al. (Bug #197475)
523  */
524 static int set_extensions_env()
526     char *oldenv = getenv("PYTHONPATH");
527     Glib::ustring tmp = INKSCAPE_EXTENSIONDIR;
528     if (oldenv != NULL) {
529         tmp += G_SEARCHPATH_SEPARATOR;
530         tmp += oldenv;
531     }
532     g_setenv("PYTHONPATH", tmp.c_str(), TRUE);
533     
534     return 0;
538 /**
539  * This is the classic main() entry point of the program, though on some
540  * architectures it might be called by something else.
541  */
542 int
543 main(int argc, char **argv)
545 #ifdef HAVE_FPSETMASK
546     /* This is inherited from Sodipodi code, where it was in #ifdef __FreeBSD__.  It's probably
547        safe to remove: the default mask is already 0 in C99, and in current FreeBSD according to
548        the fenv man page on www.freebsd.org, and in glibc according to (libc)FP Exceptions. */
549     fpsetmask(fpgetmask() & ~(FP_X_DZ | FP_X_INV));
550 #endif
552 #ifdef WIN32
553     /*
554       Set the current directory to the directory of the
555       executable.  This seems redundant, but is needed for
556       when inkscape.exe is executed from another directory.
557       We use relative paths on win32.
558       HKCR\svgfile\shell\open\command is a good example
559     */
560     Glib::ustring homedir = _win32_getExePath();
561     SetCurrentDirectory(homedir.c_str());
562     _win32_set_inkscape_env(homedir);
563     RegistryTool rt;
564     rt.setPathInfo();
565 #endif
567     // Prevents errors like "Unable to wrap GdkPixbuf..." (in nr-filter-image.cpp for example)
568     Gtk::Main::init_gtkmm_internals();
570     // Bug #197475
571     set_extensions_env();
573    /**
574     * Call bindtextdomain() for various machines's paths
575     */
576 #ifdef ENABLE_NLS
577 #ifdef WIN32
578     Glib::ustring localePath = homedir;
579     localePath += "\\";
580     localePath += PACKAGE_LOCALE_DIR;
581     bindtextdomain(GETTEXT_PACKAGE, localePath.c_str());
582 #else
583 #ifdef ENABLE_BINRELOC
584     bindtextdomain(GETTEXT_PACKAGE, BR_LOCALEDIR(""));
585 #else
586     bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
587 #endif
588 #endif
589     // Allow the user to override the locale directory by setting
590     // the environment variable INKSCAPE_LOCALEDIR.
591     char *inkscape_localedir = getenv("INKSCAPE_LOCALEDIR");
592     if (inkscape_localedir != NULL) {
593         bindtextdomain(GETTEXT_PACKAGE, inkscape_localedir);
594     }
595 #endif
597     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
599 #ifdef ENABLE_NLS
600     textdomain(GETTEXT_PACKAGE);
601 #endif
603     LIBXML_TEST_VERSION
605     Inkscape::GC::init();
607     Inkscape::Debug::Logger::init();
609     gboolean use_gui;
611 #ifndef WIN32
612     use_gui = (getenv("DISPLAY") != NULL);
613 #else
614     use_gui = TRUE;
615 #endif
616     /* Test whether with/without GUI is forced */
617     for (int i = 1; i < argc; i++) {
618         if (!strcmp(argv[i], "-z")
619             || !strcmp(argv[i], "--without-gui")
620             || !strcmp(argv[i], "-p")
621             || !strncmp(argv[i], "--print", 7)
622             || !strcmp(argv[i], "-e")
623             || !strncmp(argv[i], "--export-png", 12)
624             || !strcmp(argv[i], "-l")
625             || !strncmp(argv[i], "--export-plain-svg", 12)
626             || !strcmp(argv[i], "-i")
627             || !strncmp(argv[i], "--export-area-drawing", 21)
628             || !strcmp(argv[i], "-D")
629             || !strncmp(argv[i], "--export-area-canvas", 20)
630             || !strcmp(argv[i], "-C")
631             || !strncmp(argv[i], "--export-id", 12)
632             || !strcmp(argv[i], "-P")
633             || !strncmp(argv[i], "--export-ps", 11)
634             || !strcmp(argv[i], "-E")
635             || !strncmp(argv[i], "--export-eps", 12)
636             || !strcmp(argv[i], "-A")
637             || !strncmp(argv[i], "--export-pdf", 12)
638 #ifdef WIN32
639             || !strcmp(argv[i], "-M")
640             || !strncmp(argv[i], "--export-emf", 12)
641 #endif //WIN32
642             || !strcmp(argv[i], "-W")
643             || !strncmp(argv[i], "--query-width", 13)
644             || !strcmp(argv[i], "-H")
645             || !strncmp(argv[i], "--query-height", 14)
646             || !strcmp(argv[i], "-S")
647             || !strncmp(argv[i], "--query-all", 11)
648             || !strcmp(argv[i], "-X")
649             || !strncmp(argv[i], "--query-x", 13)
650             || !strcmp(argv[i], "-Y")
651             || !strncmp(argv[i], "--query-y", 14)
652             || !strcmp(argv[i], "--vacuum-defs")
653             || !strncmp(argv[i], "--shell", 7)
654            )
655         {
656             /* main_console handles any exports -- not the gui */
657             use_gui = FALSE;
658             break;
659         } else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "--with-gui")) {
660             use_gui = TRUE;
661             break;
662         }
663     }
665 #ifdef WIN32
666 #ifndef REPLACEARGS_ANSI
667     if ( PrintWin32::is_os_wide() )
668 #endif // REPLACEARGS_ANSI
669     {
670         // If the call fails, we'll need to convert charsets
671         needToRecodeParams = !replaceArgs( argc, argv );
672     }
673 #endif // WIN32
675     /// \todo  Should this be a static object (see inkscape.cpp)?
676     Inkscape::NSApplication::Application app(argc, argv, use_gui, sp_new_gui);
678     return app.run();
684 void fixupSingleFilename( gchar **orig, gchar **spare )
686     if ( orig && *orig && **orig ) {
687         GError *error = NULL;
688         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(*orig, -1, NULL, NULL, &error);
689         if ( newFileName )
690         {
691             *orig = newFileName;
692             if ( spare ) {
693                 *spare = newFileName;
694             }
695 //             g_message("Set a replacement fixup");
696         }
697     }
702 GSList *fixupFilenameEncoding( GSList* fl )
704     GSList *newFl = NULL;
705     while ( fl ) {
706         gchar *fn = static_cast<gchar*>(fl->data);
707         fl = g_slist_remove( fl, fl->data );
708         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(fn, -1, NULL, NULL, NULL);
709         if ( newFileName ) {
711             if ( 0 )
712             {
713                 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
714                 gchar *safeNewFn = Inkscape::IO::sanitizeString(newFileName);
715                 GtkWidget *w = gtk_message_dialog_new( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
716                                                        "Note: Converted '%s' to '%s'", safeFn, safeNewFn );
717                 gtk_dialog_run (GTK_DIALOG (w));
718                 gtk_widget_destroy (w);
719                 g_free(safeNewFn);
720                 g_free(safeFn);
721             }
723             g_free( fn );
724             fn = newFileName;
725             newFileName = 0;
726         }
727         else
728             if ( 0 )
729         {
730             gchar *safeFn = Inkscape::IO::sanitizeString(fn);
731             GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "Error: Unable to convert '%s'", safeFn );
732             gtk_dialog_run (GTK_DIALOG (w));
733             gtk_widget_destroy (w);
734             g_free(safeFn);
735         }
736         newFl = g_slist_append( newFl, fn );
737     }
738     return newFl;
741 int sp_common_main( int argc, char const **argv, GSList **flDest )
743     /// \todo fixme: Move these to some centralized location (Lauris)
744     sp_object_type_register("sodipodi:namedview", SP_TYPE_NAMEDVIEW);
745     sp_object_type_register("sodipodi:guide", SP_TYPE_GUIDE);
748     // temporarily switch gettext encoding to locale, so that help messages can be output properly
749     gchar const *charset;
750     g_get_charset(&charset);
752     bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
754     poptContext ctx = poptGetContext(NULL, argc, argv, options, 0);
755     poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
756     g_return_val_if_fail(ctx != NULL, 1);
758     /* Collect own arguments */
759     GSList *fl = sp_process_args(ctx);
760     poptFreeContext(ctx);
762     // now switch gettext back to UTF-8 (for GUI)
763     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
765     // Now let's see if the file list still holds up
766     if ( needToRecodeParams )
767     {
768         fl = fixupFilenameEncoding( fl );
769     }
771     // Check the globals for filename-fixup
772     if ( needToRecodeParams )
773     {
774         fixupSingleFilename( &sp_export_png, &sp_export_png_utf8 );
775         fixupSingleFilename( &sp_export_svg, &sp_export_svg_utf8 );
776         fixupSingleFilename( &sp_global_printer, &sp_global_printer_utf8 );
777     }
778     else
779     {
780         if ( sp_export_png )
781             sp_export_png_utf8 = g_strdup( sp_export_png );
782         if ( sp_export_svg )
783             sp_export_svg_utf8 = g_strdup( sp_export_svg );
784         if ( sp_global_printer )
785             sp_global_printer_utf8 = g_strdup( sp_global_printer );
786     }
788     // Return the list if wanted, else free it up.
789     if ( flDest ) {
790         *flDest = fl;
791         fl = 0;
792     } else {
793         while ( fl ) {
794             g_free( fl->data );
795             fl = g_slist_remove( fl, fl->data );
796         }
797     }
798     return 0;
801 static void
802 snooper(GdkEvent *event, gpointer /*data*/) {
803     if(inkscape_mapalt())  /* returns the map of the keyboard modifier to map to Alt, zero if no mapping */
804     {
805         GdkModifierType mapping=(GdkModifierType)inkscape_mapalt();
806         switch (event->type) {
807             case GDK_MOTION_NOTIFY:
808                 if(event->motion.state & mapping) {
809                     event->motion.state|=GDK_MOD1_MASK;
810                 }
811                 break;
812             case GDK_BUTTON_PRESS:
813                 if(event->button.state & mapping) {
814                     event->button.state|=GDK_MOD1_MASK;
815                 }
816                 break;
817              case GDK_KEY_PRESS:
818                  if(event->key.state & mapping) {
819                      event->key.state|=GDK_MOD1_MASK;
820                  }
821                  break;
822         default:
823             break;
824         }
825     }
826     gtk_main_do_event (event);
829 int
830 sp_main_gui(int argc, char const **argv)
832     Gtk::Main main_instance (&argc, const_cast<char ***>(&argv));
834     GSList *fl = NULL;
835     int retVal = sp_common_main( argc, argv, &fl );
836     g_return_val_if_fail(retVal == 0, 1);
838     // Add our icon directory to the search path for icon theme lookups.
839     gchar *usericondir = profile_path("icons");
840     gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), usericondir);
841     gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), INKSCAPE_PIXMAPDIR);
842     g_free(usericondir);
844     gdk_event_handler_set((GdkEventFunc)snooper, NULL, NULL);
845     Inkscape::Debug::log_display_config();
847     // Set default window icon. Obeys the theme.
848     gtk_window_set_default_icon_name("inkscape");
849     // Do things that were previously in inkscape_gtk_stock_init().
850     sp_icon_get_phys_size(GTK_ICON_SIZE_MENU);
851     Inkscape::UI::Widget::Panel::prep();
853     gboolean create_new = TRUE;
855     /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
856     inkscape_application_init(argv[0], true);
858     while (fl) {
859         if (sp_file_open((gchar *)fl->data,NULL)) {
860             create_new=FALSE;
861         }
862         fl = g_slist_remove(fl, fl->data);
863     }
864     if (create_new) {
865         sp_file_new_default();
866     }
868     Glib::signal_idle().connect(sigc::ptr_fun(&Inkscape::CmdLineAction::idle));
869     main_instance.run();
871 #ifdef WIN32
872     //We might not need anything here
873     //sp_win32_finish(); <-- this is a NOP func
874 #endif
876     return 0;
879 /**
880  * Process file list
881  */
882 void sp_process_file_list(GSList *fl)
884     while (fl) {
885         const gchar *filename = (gchar *)fl->data;
886         SPDocument *doc = Inkscape::Extension::open(NULL, filename);
887         if (doc == NULL) {
888             doc = Inkscape::Extension::open(Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), filename);
889         }
890         if (doc == NULL) {
891             g_warning("Specified document %s cannot be opened (is it a valid SVG file?)", filename);
892         } else {
893             if (sp_vacuum_defs) {
894                 vacuum_document(doc);
895             }
896             if (sp_vacuum_defs && !sp_export_svg) {
897                 // save under the name given in the command line
898                 sp_repr_save_file(doc->rdoc, filename, SP_SVG_NS_URI);
899             }
900             if (sp_global_printer) {
901                 sp_print_document_to_file(doc, sp_global_printer);
902             }
903             if (sp_export_png) {
904                 sp_do_export_png(doc);
905             }
906             if (sp_export_svg) {
907                 Inkscape::XML::Document *rdoc;
908                 Inkscape::XML::Node *repr;
909                 rdoc = sp_repr_document_new("svg:svg");
910                 repr = rdoc->root();
911                 repr = sp_document_root(doc)->updateRepr(rdoc, repr, SP_OBJECT_WRITE_BUILD);
912                 sp_repr_save_file(repr->document(), sp_export_svg, SP_SVG_NS_URI);
913             }
914             if (sp_export_ps) {
915                 do_export_ps_pdf(doc, sp_export_ps, "image/x-postscript");
916             }
917             if (sp_export_eps) {
918                 do_export_ps_pdf(doc, sp_export_eps, "image/x-e-postscript");
919             }
920             if (sp_export_pdf) {
921                 do_export_ps_pdf(doc, sp_export_pdf, "application/pdf");
922             }
923 #ifdef WIN32
924             if (sp_export_emf) {
925                 do_export_emf(doc, sp_export_emf, "image/x-emf");
926             }
927 #endif //WIN32
928             if (sp_query_all) {
929                 do_query_all (doc);
930             } else if (sp_query_width || sp_query_height) {
931                 do_query_dimension (doc, true, sp_query_width? Geom::X : Geom::Y, sp_query_id);
932             } else if (sp_query_x || sp_query_y) {
933                 do_query_dimension (doc, false, sp_query_x? Geom::X : Geom::Y, sp_query_id);
934             }
936             delete doc;
937         }
938         fl = g_slist_remove(fl, fl->data);
939     }
942 /**
943  * Run the application as an interactive shell, parsing command lines from stdin
944  * Returns -1 on error.
945  */
946 int sp_main_shell(char const* command_name)
948     int retval = 0;
950     const unsigned int buffer_size = 4096;
951     gchar *command_line = g_strnfill(buffer_size, 0);
952     g_strlcpy(command_line, command_name, buffer_size);
953     gsize offset = g_strlcat(command_line, " ", buffer_size);
954     gsize sizeLeft = buffer_size - offset;
955     gchar *useme = command_line + offset;
957     fprintf(stdout, "Inkscape %s interactive shell mode. Type 'quit' to quit.\n", Inkscape::version_string);
958     fflush(stdout);
959     char* linedata = 0;
960     do {
961         fprintf(stdout, ">");
962         fflush(stdout);
963         if ((linedata = fgets(useme, sizeLeft, stdin))) {
964             size_t len = strlen(useme);
965             if ( (len >= sizeLeft - 1) || (useme[len - 1] != '\n') ) {
966                 fprintf(stdout, "ERROR: Command line too long\n");
967                 // Consume rest of line
968                 retval = -1; // If the while loop completes, this remains -1
969                 while (fgets(useme, sizeLeft, stdin) && retval) {
970                     len = strlen(command_line);
971                     if ( (len < buffer_size) && (command_line[len-1] == '\n') ) {
972                         retval = 0;
973                     }
974                 }
975             } else {
976                 useme[--len] = '\0';  // Strip newline
977                 if (useme[len - 1] == '\r') {
978                     useme[--len] = '\0';
979                 }
980                 if ( strcmp(useme, "quit") == 0 ) {
981                     // Time to quit
982                     fflush(stdout);
983                     linedata = 0; // mark for exit
984                 } else if ( len < 1 ) {
985                     // blank string. Do nothing.
986                 } else {
987                     GError* parseError = 0;
988                     gchar** argv = 0;
989                     gint argc = 0;
990                     if ( g_shell_parse_argv(command_line, &argc, &argv, &parseError) ) {
991                         poptContext ctx = poptGetContext(NULL, argc, const_cast<const gchar**>(argv), options, 0);
992                         poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
993                         if ( ctx ) {
994                             GSList *fl = sp_process_args(ctx);
995                             sp_process_file_list(fl);
996                             poptFreeContext(ctx);
997                         } else {
998                             retval = 1; // not sure why. But this was the previous return value
999                         }
1000                         resetCommandlineGlobals();
1001                         g_strfreev(argv);
1002                     } else {
1003                         g_warning("Cannot parse commandline: %s", useme);
1004                     }
1005                 }
1006             }
1007         } // if (linedata...
1008     } while (linedata && (retval == 0));
1010     g_free(command_line);
1011     return retval;
1014 int sp_main_console(int argc, char const **argv)
1016     /* We are started in text mode */
1018     /* Do this g_type_init(), so that we can use Xft/Freetype2 (Pango)
1019      * in a non-Gtk environment.  Used in libnrtype's
1020      * FontInstance.cpp and FontFactory.cpp.
1021      * http://mail.gnome.org/archives/gtk-list/2003-December/msg00063.html
1022      */
1023     g_type_init();
1024     char **argv2 = const_cast<char **>(argv);
1025     gtk_init_check( &argc, &argv2 );
1026     //setlocale(LC_ALL, "");
1028     GSList *fl = NULL;
1029     int retVal = sp_common_main( argc, argv, &fl );
1030     g_return_val_if_fail(retVal == 0, 1);
1032     if (fl == NULL && !sp_shell) {
1033         g_print("Nothing to do!\n");
1034         exit(0);
1035     }
1037     inkscape_application_init(argv[0], false);
1039     if (sp_shell) {
1040         sp_main_shell(argv[0]); // Run as interactive shell
1041         exit(0);
1042     } else {
1043         sp_process_file_list(fl); // Normal command line invokation
1044     }
1046     return 0;
1049 static void
1050 do_query_dimension (SPDocument *doc, bool extent, Geom::Dim2 const axis, const gchar *id)
1052     SPObject *o = NULL;
1054     if (id) {
1055         o = doc->getObjectById(id);
1056         if (o) {
1057             if (!SP_IS_ITEM (o)) {
1058                 g_warning("Object with id=\"%s\" is not a visible item. Cannot query dimensions.", id);
1059                 return;
1060             }
1061         } else {
1062             g_warning("Object with id=\"%s\" is not found. Cannot query dimensions.", id);
1063             return;
1064         }
1065     } else {
1066         o = SP_DOCUMENT_ROOT(doc);
1067     }
1069     if (o) {
1070         sp_document_ensure_up_to_date (doc);
1071         SPItem *item = ((SPItem *) o);
1073         // "true" SVG bbox for scripting
1074         Geom::OptRect area = item->getBounds(sp_item_i2doc_affine(item));
1075         if (area) {
1076             Inkscape::SVGOStringStream os;
1077             if (extent) {
1078                 os << area->dimensions()[axis];
1079             } else {
1080                 os << area->min()[axis];
1081             }
1082             g_print ("%s", os.str().c_str());
1083         } else {
1084             g_print("0");
1085         }
1086     }
1089 static void
1090 do_query_all (SPDocument *doc)
1092     SPObject *o = NULL;
1094     o = SP_DOCUMENT_ROOT(doc);
1096     if (o) {
1097         sp_document_ensure_up_to_date (doc);
1098         do_query_all_recurse(o);
1099     }
1102 static void
1103 do_query_all_recurse (SPObject *o)
1105     SPItem *item = ((SPItem *) o);
1106     if (o->id && SP_IS_ITEM(item)) {
1107         Geom::OptRect area = item->getBounds(sp_item_i2doc_affine(item));
1108         if (area) {
1109             Inkscape::SVGOStringStream os;
1110             os << o->id;
1111             os << "," << area->min()[Geom::X];
1112             os << "," << area->min()[Geom::Y];
1113             os << "," << area->dimensions()[Geom::X];
1114             os << "," << area->dimensions()[Geom::Y];
1115             g_print ("%s\n", os.str().c_str());
1116         }
1117     }
1119     SPObject *child = o->children;
1120     while (child) {
1121         do_query_all_recurse (child);
1122         child = child->next;
1123     }
1127 static void
1128 sp_do_export_png(SPDocument *doc)
1130     const gchar *filename = NULL;
1131     gdouble dpi = 0.0;
1133     if (sp_export_use_hints && (!sp_export_id && !sp_export_area_drawing)) {
1134         g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored.");
1135     }
1137     GSList *items = NULL;
1139     Geom::Rect area;
1140     if (sp_export_id || sp_export_area_drawing) {
1142         SPObject *o = NULL;
1143         SPObject *o_area = NULL;
1144         if (sp_export_id && sp_export_area_drawing) {
1145             o = doc->getObjectById(sp_export_id);
1146             o_area = SP_DOCUMENT_ROOT (doc);
1147         } else if (sp_export_id) {
1148             o = doc->getObjectById(sp_export_id);
1149             o_area = o;
1150         } else if (sp_export_area_drawing) {
1151             o = SP_DOCUMENT_ROOT (doc);
1152             o_area = o;
1153         }
1155         if (o) {
1156             if (!SP_IS_ITEM (o)) {
1157                 g_warning("Object with id=\"%s\" is not a visible item. Nothing exported.", sp_export_id);
1158                 return;
1159             }
1161             items = g_slist_prepend (items, SP_ITEM(o));
1163             if (sp_export_id_only) {
1164                 g_print("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id);
1165             }
1167             if (sp_export_use_hints) {
1169                 // retrieve export filename hint
1170                 const gchar *fn_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-filename");
1171                 if (fn_hint) {
1172                     if (sp_export_png) {
1173                         g_warning ("Using export filename from the command line (--export-png). Filename hint %s is ignored.", fn_hint);
1174                         filename = sp_export_png;
1175                     } else {
1176                         filename = fn_hint;
1177                     }
1178                 } else {
1179                     g_warning ("Export filename hint not found for the object.");
1180                     filename = sp_export_png;
1181                 }
1183                 // retrieve export dpi hints
1184                 const gchar *dpi_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
1185                 if (dpi_hint) {
1186                     if (sp_export_dpi || sp_export_width || sp_export_height) {
1187                         g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint);
1188                     } else {
1189                         dpi = atof(dpi_hint);
1190                     }
1191                 } else {
1192                     g_warning ("Export DPI hint not found for the object.");
1193                 }
1195             }
1197             // write object bbox to area
1198             sp_document_ensure_up_to_date (doc);
1199             Geom::OptRect areaMaybe;
1200             sp_item_invoke_bbox((SPItem *) o_area, areaMaybe, sp_item_i2d_affine((SPItem *) o_area), TRUE);
1201             if (areaMaybe) {
1202                 area = *areaMaybe;
1203             } else {
1204                 g_warning("Unable to determine a valid bounding box. Nothing exported.");
1205                 return;
1206             }
1207         } else {
1208             g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
1209             return;
1210         }
1211     }
1213     if (sp_export_area) {
1214         /* Try to parse area (given in SVG pixels) */
1215         gdouble x0,y0,x1,y1;
1216         if (!sscanf(sp_export_area, "%lg:%lg:%lg:%lg", &x0, &y0, &x1, &y1) == 4) {
1217             g_warning("Cannot parse export area '%s'; use 'x0:y0:x1:y1'. Nothing exported.", sp_export_area);
1218             return;
1219         }
1220         area = Geom::Rect(Geom::Interval(x0,x1), Geom::Interval(y0,y1));
1221     } else if (sp_export_area_canvas || !(sp_export_id || sp_export_area_drawing)) {
1222         /* Export the whole canvas */
1223         sp_document_ensure_up_to_date (doc);
1224         Geom::Point origin (SP_ROOT(doc->root)->x.computed, SP_ROOT(doc->root)->y.computed);
1225         area = Geom::Rect(origin, origin + sp_document_dimensions(doc));
1226     }
1228     // set filename and dpi from options, if not yet set from the hints
1229     if (!filename) {
1230         if (!sp_export_png) {
1231             g_warning ("No export filename given and no filename hint. Nothing exported.");
1232             return;
1233         }
1234         filename = sp_export_png;
1235     }
1237     if (sp_export_dpi && dpi == 0.0) {
1238         dpi = atof(sp_export_dpi);
1239         if ((dpi < 0.1) || (dpi > 10000.0)) {
1240             g_warning("DPI value %s out of range [0.1 - 10000.0]. Nothing exported.", sp_export_dpi);
1241             return;
1242         }
1243         g_print("DPI: %g\n", dpi);
1244     }
1246     if (sp_export_area_snap) {
1247         round_rectangle_outwards(area);
1248     }
1250     // default dpi
1251     if (dpi == 0.0) {
1252         dpi = PX_PER_IN;
1253     }
1255     unsigned long int width = 0;
1256     unsigned long int height = 0;
1258     if (sp_export_width) {
1259         errno=0;
1260         width = strtoul(sp_export_width, NULL, 0);
1261         if ((width < 1) || (width > PNG_UINT_31_MAX) || (errno == ERANGE) ) {
1262             g_warning("Export width %lu out of range (1 - %lu). Nothing exported.", width, (unsigned long int)PNG_UINT_31_MAX);
1263             return;
1264         }
1265         dpi = (gdouble) width * PX_PER_IN / area.width();
1266     }
1268     if (sp_export_height) {
1269         errno=0;
1270         height = strtoul(sp_export_height, NULL, 0);
1271         if ((height < 1) || (height > PNG_UINT_31_MAX)) {
1272             g_warning("Export height %lu out of range (1 - %lu). Nothing exported.", height, (unsigned long int)PNG_UINT_31_MAX);
1273             return;
1274         }
1275         dpi = (gdouble) height * PX_PER_IN / area.height();
1276     }
1278     if (!sp_export_width) {
1279         width = (unsigned long int) (area.width() * dpi / PX_PER_IN + 0.5);
1280     }
1282     if (!sp_export_height) {
1283         height = (unsigned long int) (area.height() * dpi / PX_PER_IN + 0.5);
1284     }
1286     guint32 bgcolor = 0x00000000;
1287     if (sp_export_background) {
1288         // override the page color
1289         bgcolor = sp_svg_read_color(sp_export_background, 0xffffff00);
1290         bgcolor |= 0xff; // default is no opacity
1291     } else {
1292         // read from namedview
1293         Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
1294         if (nv && nv->attribute("pagecolor"))
1295             bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
1296         if (nv && nv->attribute("inkscape:pageopacity"))
1297             bgcolor |= SP_COLOR_F_TO_U(sp_repr_get_double_attribute (nv, "inkscape:pageopacity", 1.0));
1298     }
1300     if (sp_export_background_opacity) {
1301         // override opacity
1302         gfloat value;
1303         if (sp_svg_number_read_f (sp_export_background_opacity, &value)) {
1304             if (value > 1.0) {
1305                 value = CLAMP (value, 1.0f, 255.0f);
1306                 bgcolor &= (guint32) 0xffffff00;
1307                 bgcolor |= (guint32) floor(value);
1308             } else {
1309                 value = CLAMP (value, 0.0f, 1.0f);
1310                 bgcolor &= (guint32) 0xffffff00;
1311                 bgcolor |= SP_COLOR_F_TO_U(value);
1312             }
1313         }
1314     }
1316     g_print("Background RRGGBBAA: %08x\n", bgcolor);
1318     g_print("Area %g:%g:%g:%g exported to %lu x %lu pixels (%g dpi)\n", area[Geom::X][0], area[Geom::Y][0], area[Geom::X][1], area[Geom::Y][1], width, height, dpi);
1320     g_print("Bitmap saved as: %s\n", filename);
1322     if ((width >= 1) && (height >= 1) && (width <= PNG_UINT_31_MAX) && (height <= PNG_UINT_31_MAX)) {
1323         sp_export_png_file(doc, filename, area, width, height, dpi, dpi, bgcolor, NULL, NULL, true, sp_export_id_only ? items : NULL);
1324     } else {
1325         g_warning("Calculated bitmap dimensions %lu %lu are out of range (1 - %lu). Nothing exported.", width, height, (unsigned long int)PNG_UINT_31_MAX);
1326     }
1328     g_slist_free (items);
1332 /**
1333  *  Perform a PDF/PS/EPS export
1334  *
1335  *  \param doc Document to export.
1336  *  \param uri URI to export to.
1337  *  \param mime MIME type to export as.
1338  */
1340 static void do_export_ps_pdf(SPDocument* doc, gchar const* uri, char const* mime)
1342     Inkscape::Extension::DB::OutputList o;
1343     Inkscape::Extension::db.get_output_list(o);
1344     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1345     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1346         i++;
1347     }
1349     if (i == o.end())
1350     {
1351         g_warning ("Could not find an extension to export to MIME type %s.", mime);
1352         return;
1353     }
1355     if (sp_export_id) {
1356         SPObject *o = doc->getObjectById(sp_export_id);
1357         if (o == NULL) {
1358             g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
1359             return;
1360         }
1361         (*i)->set_param_string ("exportId", sp_export_id);
1362     } else {
1363         (*i)->set_param_string ("exportId", "");
1364     }
1366     if (sp_export_area_canvas && sp_export_area_drawing) {
1367         g_warning ("You cannot use --export-area-canvas and --export-area-drawing at the same time; only the former will take effect.");
1368         sp_export_area_drawing = false;
1369     }
1371     if (sp_export_area_drawing) {
1372         (*i)->set_param_bool ("areaDrawing", TRUE);
1373     } else {
1374         (*i)->set_param_bool ("areaDrawing", FALSE);
1375     }
1377     if (sp_export_area_canvas) {
1378         if (sp_export_eps) {
1379             g_warning ("EPS cannot have its bounding box extend beyond its content, so if your drawing is smaller than the canvas, --export-area-canvas will clip it to drawing.");
1380         } 
1381         (*i)->set_param_bool ("areaCanvas", TRUE);
1382     } else {
1383         (*i)->set_param_bool ("areaCanvas", FALSE);
1384     }
1386     if (!sp_export_area_drawing && !sp_export_area_canvas && !sp_export_id) { 
1387         // neither is set, set canvas as default for ps/pdf and drawing for eps
1388         if (sp_export_eps) {
1389             try {
1390                (*i)->set_param_bool("areaDrawing", TRUE);
1391             } catch (...) {}
1392         } 
1393     }
1395     if (sp_export_text_to_path) {
1396         (*i)->set_param_bool("textToPath", TRUE);
1397     } else {
1398         (*i)->set_param_bool("textToPath", FALSE);
1399     }
1401     if (sp_export_ignore_filters) {
1402         (*i)->set_param_bool("blurToBitmap", FALSE);
1403     } else {
1404         (*i)->set_param_bool("blurToBitmap", TRUE);
1405     }
1407     (*i)->save(doc, uri);
1410 #ifdef WIN32
1411 /**
1412  *  Export a document to EMF
1413  *
1414  *  \param doc Document to export.
1415  *  \param uri URI to export to.
1416  *  \param mime MIME type to export as (should be "image/x-emf")
1417  */
1419 static void do_export_emf(SPDocument* doc, gchar const* uri, char const* mime)
1421     Inkscape::Extension::DB::OutputList o;
1422     Inkscape::Extension::db.get_output_list(o);
1423     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1424     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1425         i++;
1426     }
1428     if (i == o.end())
1429     {
1430         g_warning ("Could not find an extension to export to MIME type %s.", mime);
1431         return;
1432     }
1434     (*i)->save(doc, uri);
1436 #endif //WIN32
1438 #ifdef WIN32
1439 bool replaceArgs( int& argc, char**& argv )
1441     bool worked = false;
1443 #ifdef REPLACEARGS_DEBUG
1444     MessageBoxA( NULL, "GetCommandLineW() getting called", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1445 #endif // REPLACEARGS_DEBUG
1447     wchar_t* line = GetCommandLineW();
1448     if ( line )
1449     {
1450 #ifdef REPLACEARGS_DEBUG
1451         {
1452             gchar* utf8Line = g_utf16_to_utf8( (gunichar2*)line, -1, NULL, NULL, NULL );
1453             if ( utf8Line )
1454             {
1455                 gchar *safe = Inkscape::IO::sanitizeString(utf8Line);
1456                 {
1457                     char tmp[strlen(safe) + 32];
1458                     snprintf( tmp, sizeof(tmp), "GetCommandLineW() = '%s'", safe );
1459                     MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1460                 }
1461             }
1462         }
1463 #endif // REPLACEARGS_DEBUG
1465         int numArgs = 0;
1466         wchar_t** parsed = CommandLineToArgvW( line, &numArgs );
1468 #ifdef REPLACEARGS_ANSI
1469 // test code for trying things on Win95/98/ME
1470         if ( !parsed )
1471         {
1472 #ifdef REPLACEARGS_DEBUG
1473             MessageBoxA( NULL, "Unable to process command-line. Faking it", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1474 #endif // REPLACEARGS_DEBUG
1475             int lineLen = wcslen(line) + 1;
1476             wchar_t* lineDup = new wchar_t[lineLen];
1477             wcsncpy( lineDup, line, lineLen );
1479             int pos = 0;
1480             bool inQuotes = false;
1481             bool inWhitespace = true;
1482             std::vector<int> places;
1483             while ( lineDup[pos] )
1484             {
1485                 if ( inQuotes )
1486                 {
1487                     if ( lineDup[pos] == L'"' )
1488                     {
1489                         inQuotes = false;
1490                     }
1491                 }
1492                 else if ( lineDup[pos] == L'"' )
1493                 {
1494                     inQuotes = true;
1495                     inWhitespace = false;
1496                     places.push_back(pos);
1497                 }
1498                 else if ( lineDup[pos] == L' ' || lineDup[pos] == L'\t' )
1499                 {
1500                     if ( !inWhitespace )
1501                     {
1502                         inWhitespace = true;
1503                         lineDup[pos] = 0;
1504                     }
1505                 }
1506                 else if ( inWhitespace && (lineDup[pos] != L' ' && lineDup[pos] != L'\t') )
1507                 {
1508                     inWhitespace = false;
1509                     places.push_back(pos);
1510                 }
1511                 else
1512                 {
1513                     // consume
1514                 }
1515                 pos++;
1516             }
1517 #ifdef REPLACEARGS_DEBUG
1518             {
1519                 char tmp[256];
1520                 snprintf( tmp, sizeof(tmp), "Counted %d args", places.size() );
1521                 MessageBoxA( NULL, tmp, "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1522             }
1523 #endif // REPLACEARGS_DEBUG
1525             wchar_t** block = new wchar_t*[places.size()];
1526             int i = 0;
1527             for ( std::vector<int>::iterator it = places.begin(); it != places.end(); it++ )
1528             {
1529                 block[i++] = &lineDup[*it];
1530             }
1531             parsed = block;
1532             numArgs = places.size();
1533         }
1534 #endif // REPLACEARGS_ANSI
1536         if ( parsed )
1537         {
1538             std::vector<wchar_t*>expandedArgs;
1539             if ( numArgs > 0 )
1540             {
1541                 expandedArgs.push_back( parsed[0] );
1542             }
1544             for ( int i1 = 1; i1 < numArgs; i1++ )
1545             {
1546                 bool wildcarded = (wcschr(parsed[i1], L'?') != NULL) || (wcschr(parsed[i1], L'*') != NULL);
1547                 wildcarded &= parsed[i1][0] != L'"';
1548                 wildcarded &= parsed[i1][0] != L'-';
1549                 if ( wildcarded )
1550                 {
1551 #ifdef REPLACEARGS_ANSI
1552                     WIN32_FIND_DATAA data;
1553 #else
1554                     WIN32_FIND_DATAW data;
1555 #endif // REPLACEARGS_ANSI
1557                     memset((void *)&data, 0, sizeof(data));
1559                     int baseLen = wcslen(parsed[i1]) + 2;
1560                     wchar_t* base = new wchar_t[baseLen];
1561                     wcsncpy( base, parsed[i1], baseLen );
1562                     wchar_t* last = wcsrchr( base, L'\\' );
1563                     if ( last )
1564                     {
1565                         last[1] = 0;
1566                     }
1567                     else
1568                     {
1569                         base[0] = 0;
1570                     }
1571                     baseLen = wcslen( base );
1573 #ifdef REPLACEARGS_ANSI
1574                     char target[MAX_PATH];
1575                     if ( WideCharToMultiByte( CP_ACP, 0, parsed[i1], -1, target, sizeof(target), NULL, NULL) )
1576                     {
1577                         HANDLE hf = FindFirstFileA( target, &data );
1578 #else
1579                         HANDLE hf = FindFirstFileW( parsed[i1], &data );
1580 #endif // REPLACEARGS_ANSI
1581                         if ( hf != INVALID_HANDLE_VALUE )
1582                         {
1583                             BOOL found = TRUE;
1584                             do
1585                             {
1586 #ifdef REPLACEARGS_ANSI
1587                                 int howMany = MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, NULL, 0 );
1588                                 if ( howMany > 0 )
1589                                 {
1590                                     howMany += baseLen;
1591                                     wchar_t* tmp = new wchar_t[howMany + 1];
1592                                     wcsncpy( tmp, base, howMany + 1 );
1593                                     MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, tmp + baseLen, howMany + 1 - baseLen );
1594                                     expandedArgs.push_back( tmp );
1595                                     found = FindNextFileA( hf, &data );
1596                                 }
1597 #else
1598                                 int howMany = wcslen(data.cFileName) + baseLen;
1599                                 wchar_t* tmp = new wchar_t[howMany + 1];
1600                                 wcsncpy( tmp, base, howMany + 1 );
1601                                 wcsncat( tmp, data.cFileName, howMany + 1 );
1602                                 expandedArgs.push_back( tmp );
1603                                 found = FindNextFileW( hf, &data );
1604 #endif // REPLACEARGS_ANSI
1605                             } while ( found );
1607                             FindClose( hf );
1608                         }
1609                         else
1610                         {
1611                             expandedArgs.push_back( parsed[i1] );
1612                         }
1613 #ifdef REPLACEARGS_ANSI
1614                     }
1615 #endif // REPLACEARGS_ANSI
1617                     delete[] base;
1618                 }
1619                 else
1620                 {
1621                     expandedArgs.push_back( parsed[i1] );
1622                 }
1623             }
1625             {
1626                 wchar_t** block = new wchar_t*[expandedArgs.size()];
1627                 int iz = 0;
1628                 for ( std::vector<wchar_t*>::iterator it = expandedArgs.begin(); it != expandedArgs.end(); it++ )
1629                 {
1630                     block[iz++] = *it;
1631                 }
1632                 parsed = block;
1633                 numArgs = expandedArgs.size();
1634             }
1636             std::vector<gchar*> newArgs;
1637             for ( int i = 0; i < numArgs; i++ )
1638             {
1639                 gchar* replacement = g_utf16_to_utf8( (gunichar2*)parsed[i], -1, NULL, NULL, NULL );
1640                 if ( replacement )
1641                 {
1642 #ifdef REPLACEARGS_DEBUG
1643                     gchar *safe2 = Inkscape::IO::sanitizeString(replacement);
1645                     if ( safe2 )
1646                     {
1647                         {
1648                             char tmp[1024];
1649                             snprintf( tmp, sizeof(tmp), "    [%2d] = '%s'", i, safe2 );
1650                             MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1651                         }
1652                         g_free( safe2 );
1653                     }
1654 #endif // REPLACEARGS_DEBUG
1656                     newArgs.push_back( replacement );
1657                 }
1658                 else
1659                 {
1660                     newArgs.push_back( blankParam );
1661                 }
1662             }
1664             // Now push our munged params to be the new argv and argc
1665             {
1666                 char** block = new char*[newArgs.size()];
1667                 int iz = 0;
1668                 for ( std::vector<char*>::iterator it = newArgs.begin(); it != newArgs.end(); it++ )
1669                 {
1670                     block[iz++] = *it;
1671                 }
1672                 argv = block;
1673                 argc = newArgs.size();
1674                 worked = true;
1675             }
1676         }
1677 #ifdef REPLACEARGS_DEBUG
1678         else
1679         {
1680             MessageBoxA( NULL, "Unable to process command-line", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1681         }
1682 #endif // REPLACEARGS_DEBUG
1683     }
1684 #ifdef REPLACEARGS_DEBUG
1685     else
1686     {
1687         {
1688             MessageBoxA( NULL,  "Unable to fetch result from GetCommandLineW()", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1689         }
1691         char* line2 = GetCommandLineA();
1692         if ( line2 )
1693         {
1694             gchar *safe = Inkscape::IO::sanitizeString(line2);
1695             {
1696                 {
1697                     char tmp[strlen(safe) + 32];
1698                     snprintf( tmp, sizeof(tmp), "GetCommandLineA() = '%s'", safe );
1699                     MessageBoxA( NULL, tmp, "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1700                 }
1701             }
1702         }
1703         else
1704         {
1705             MessageBoxA( NULL, "Unable to fetch result from GetCommandLineA()", "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1706         }
1707     }
1708 #endif // REPLACEARGS_DEBUG
1710     return worked;
1712 #endif // WIN32
1714 static GSList *
1715 sp_process_args(poptContext ctx)
1717     GSList *fl = NULL;
1719     gint a;
1720     while ((a = poptGetNextOpt(ctx)) != -1) {
1721         switch (a) {
1722             case SP_ARG_FILE: {
1723                 gchar const *fn = poptGetOptArg(ctx);
1724                 if (fn != NULL) {
1725                     fl = g_slist_append(fl, g_strdup(fn));
1726                 }
1727                 break;
1728             }
1729             case SP_ARG_VERSION: {
1730                 printf("Inkscape %s (%s)\n", Inkscape::version_string, __DATE__);
1731                 exit(0);
1732                 break;
1733             }
1734             case SP_ARG_EXTENSIONDIR: {
1735                 printf("%s\n", INKSCAPE_EXTENSIONDIR);
1736                 exit(0);
1737                 break;
1738             }
1739             case SP_ARG_VERB_LIST: {
1740                 // This really shouldn't go here, we should init the app.
1741                 // But, since we're just exiting in this path, there is
1742                 // no harm, and this is really a better place to put
1743                 // everything else.
1744                 Inkscape::Extension::init();
1745                 Inkscape::Verb::list();
1746                 exit(0);
1747                 break;
1748             }
1749             case SP_ARG_VERB:
1750             case SP_ARG_SELECT: {
1751                 gchar const *arg = poptGetOptArg(ctx);
1752                 if (arg != NULL) {
1753                     // printf("Adding in: %s\n", arg);
1754                     new Inkscape::CmdLineAction((a == SP_ARG_VERB), arg);
1755                 }
1756                 break;
1757             }
1758             case POPT_ERROR_BADOPT: {
1759                 g_warning ("Invalid option %s", poptBadOption(ctx, 0));
1760                 exit(1);
1761                 break;
1762             }
1763             default: {
1764                 break;
1765             }
1766         }
1767     }
1769     gchar const ** const args = poptGetArgs(ctx);
1770     if (args != NULL) {
1771         for (unsigned i = 0; args[i] != NULL; i++) {
1772             fl = g_slist_append(fl, g_strdup(args[i]));
1773         }
1774     }
1776     return fl;
1780 /*
1781   Local Variables:
1782   mode:c++
1783   c-file-style:"stroustrup"
1784   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1785   indent-tabs-mode:nil
1786   fill-column:99
1787   End:
1788 */
1789 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :