Code

Applied cleaned-up patch for 'server' or 'shell' mode.
[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>
40 #include <popt.h>
41 #ifndef POPT_TABLEEND
42 #define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL }
43 #endif /* Not def: POPT_TABLEEND */
45 #include <libxml/tree.h>
46 #include <glib-object.h>
47 #include <gtk/gtkmain.h>
48 #include <gtk/gtksignal.h>
49 #include <gtk/gtkwindow.h>
50 #include <gtk/gtkbox.h>
52 #include "gc-core.h"
54 #include "macros.h"
55 #include "file.h"
56 #include "document.h"
57 #include "sp-object.h"
58 #include "interface.h"
59 #include "print.h"
60 #include "color.h"
61 #include "sp-item.h"
62 #include "sp-root.h"
63 #include "unit-constants.h"
65 #include "svg/svg.h"
66 #include "svg/svg-color.h"
67 #include "svg/stringstream.h"
69 #include "inkscape-private.h"
70 #include "inkscape-stock.h"
71 #include "inkscape_version.h"
73 #include "sp-namedview.h"
74 #include "sp-guide.h"
75 #include "sp-object-repr.h"
76 #include "xml/repr.h"
78 #include "io/sys.h"
80 #include "debug/logger.h"
81 #include "debug/log-display-config.h"
83 #include "helper/png-write.h"
85 #include <extension/extension.h>
86 #include <extension/system.h>
87 #include <extension/db.h>
88 #include <extension/output.h>
90 #ifdef WIN32
91 //#define REPLACEARGS_ANSI
92 //#define REPLACEARGS_DEBUG
94 #include "registrytool.h"
96 #include "extension/internal/win32.h"
97 using Inkscape::Extension::Internal::PrintWin32;
99 #endif // WIN32
101 #include "extension/init.h"
103 #include <glibmm/i18n.h>
104 #include <gtkmm/main.h>
106 #ifndef HAVE_BIND_TEXTDOMAIN_CODESET
107 #define bind_textdomain_codeset(p,c)
108 #endif
110 #include "application/application.h"
112 #include "main-cmdlineact.h"
114 #include <png.h>
115 #include <errno.h>
117 enum {
118     SP_ARG_NONE,
119     SP_ARG_NOGUI,
120     SP_ARG_GUI,
121     SP_ARG_FILE,
122     SP_ARG_PRINT,
123     SP_ARG_EXPORT_PNG,
124     SP_ARG_EXPORT_DPI,
125     SP_ARG_EXPORT_AREA,
126     SP_ARG_EXPORT_AREA_DRAWING,
127     SP_ARG_EXPORT_AREA_CANVAS,
128     SP_ARG_EXPORT_AREA_SNAP,
129     SP_ARG_EXPORT_WIDTH,
130     SP_ARG_EXPORT_HEIGHT,
131     SP_ARG_EXPORT_ID,
132     SP_ARG_EXPORT_ID_ONLY,
133     SP_ARG_EXPORT_USE_HINTS,
134     SP_ARG_EXPORT_BACKGROUND,
135     SP_ARG_EXPORT_BACKGROUND_OPACITY,
136     SP_ARG_EXPORT_SVG,
137     SP_ARG_EXPORT_PS,
138     SP_ARG_EXPORT_EPS,
139     SP_ARG_EXPORT_PDF,
140 #ifdef WIN32
141     SP_ARG_EXPORT_EMF,
142 #endif //WIN32
143     SP_ARG_EXPORT_TEXT_TO_PATH,
144     SP_ARG_EXPORT_FONT,
145     SP_ARG_EXPORT_BBOX_PAGE,
146     SP_ARG_EXTENSIONDIR,
147     SP_ARG_FIT_PAGE_TO_DRAWING,
148     SP_ARG_QUERY_X,
149     SP_ARG_QUERY_Y,
150     SP_ARG_QUERY_WIDTH,
151     SP_ARG_QUERY_HEIGHT,
152     SP_ARG_QUERY_ALL,
153     SP_ARG_QUERY_ID,
154     SP_ARG_SHELL,
155     SP_ARG_VERSION,
156     SP_ARG_VACUUM_DEFS,
157     SP_ARG_VERB_LIST,
158     SP_ARG_VERB,
159     SP_ARG_SELECT,
160     SP_ARG_LAST
161 };
163 int sp_main_gui(int argc, char const **argv);
164 int sp_main_console(int argc, char const **argv);
165 static void sp_do_export_png(SPDocument *doc);
166 static void do_export_ps(SPDocument* doc, gchar const* uri, char const *mime);
167 static void do_export_pdf(SPDocument* doc, gchar const* uri, char const *mime);
168 #ifdef WIN32
169 static void do_export_emf(SPDocument* doc, gchar const* uri, char const *mime);
170 #endif //WIN32
171 static void do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id);
172 static void do_query_all (SPDocument *doc);
173 static void do_query_all_recurse (SPObject *o);
175 static gchar *sp_global_printer = NULL;
176 static gchar *sp_export_png = NULL;
177 static gchar *sp_export_dpi = NULL;
178 static gchar *sp_export_area = NULL;
179 static gboolean sp_export_area_drawing = FALSE;
180 static gboolean sp_export_area_canvas = FALSE;
181 static gchar *sp_export_width = NULL;
182 static gchar *sp_export_height = NULL;
183 static gchar *sp_export_id = NULL;
184 static gchar *sp_export_background = NULL;
185 static gchar *sp_export_background_opacity = NULL;
186 static gboolean sp_export_area_snap = FALSE;
187 static gboolean sp_export_use_hints = FALSE;
188 static gboolean sp_export_id_only = FALSE;
189 static gchar *sp_export_svg = NULL;
190 static gchar *sp_export_ps = NULL;
191 static gchar *sp_export_eps = NULL;
192 static gchar *sp_export_pdf = NULL;
193 #ifdef WIN32
194 static gchar *sp_export_emf = NULL;
195 #endif //WIN32
196 static gboolean sp_export_text_to_path = FALSE;
197 static gboolean sp_export_font = FALSE;
198 static gboolean sp_export_bbox_page = FALSE;
199 static gboolean sp_query_x = FALSE;
200 static gboolean sp_query_y = FALSE;
201 static gboolean sp_query_width = FALSE;
202 static gboolean sp_query_height = FALSE;
203 static gboolean sp_query_all = FALSE;
204 static gchar *sp_query_id = NULL;
205 static int sp_new_gui = FALSE;
206 static gboolean sp_shell = FALSE;
207 static gboolean sp_vacuum_defs = FALSE;
209 static gchar *sp_export_png_utf8 = NULL;
210 static gchar *sp_export_svg_utf8 = NULL;
211 static gchar *sp_global_printer_utf8 = NULL;
214 /**
215  *  Reset variables to default values.
216  */
217 static void resetCommandlineGlobals() {
218         sp_global_printer = NULL;
219         sp_export_png = NULL;
220         sp_export_dpi = NULL;
221         sp_export_area = NULL;
222         sp_export_area_drawing = FALSE;
223         sp_export_area_canvas = FALSE;
224         sp_export_width = NULL;
225         sp_export_height = NULL;
226         sp_export_id = NULL;
227         sp_export_background = NULL;
228         sp_export_background_opacity = NULL;
229         sp_export_area_snap = FALSE;
230         sp_export_use_hints = FALSE;
231         sp_export_id_only = FALSE;
232         sp_export_svg = NULL;
233         sp_export_ps = NULL;
234         sp_export_eps = NULL;
235         sp_export_pdf = NULL;
236         #ifdef WIN32
237         sp_export_emf = NULL;
238         #endif //WIN32
239         sp_export_text_to_path = FALSE;
240         sp_export_font = FALSE;
241         sp_export_bbox_page = FALSE;
242         sp_query_x = FALSE;
243         sp_query_y = FALSE;
244         sp_query_width = FALSE;
245         sp_query_height = FALSE;
246         sp_query_all = FALSE;
247         sp_query_id = NULL;
248         sp_vacuum_defs = FALSE;
250         sp_export_png_utf8 = NULL;
251         sp_export_svg_utf8 = NULL;
252         sp_global_printer_utf8 = NULL;
255 #ifdef WIN32
256 static bool replaceArgs( int& argc, char**& argv );
257 #endif
258 static GSList *sp_process_args(poptContext ctx);
259 struct poptOption options[] = {
260     {"version", 'V',
261      POPT_ARG_NONE, NULL, SP_ARG_VERSION,
262      N_("Print the Inkscape version number"),
263      NULL},
265     {"without-gui", 'z',
266      POPT_ARG_NONE, NULL, SP_ARG_NOGUI,
267      N_("Do not use X server (only process files from console)"),
268      NULL},
270     {"with-gui", 'g',
271      POPT_ARG_NONE, NULL, SP_ARG_GUI,
272      N_("Try to use X server (even if $DISPLAY is not set)"),
273      NULL},
275     {"file", 'f',
276      POPT_ARG_STRING, NULL, SP_ARG_FILE,
277      N_("Open specified document(s) (option string may be excluded)"),
278      N_("FILENAME")},
280     {"print", 'p',
281      POPT_ARG_STRING, &sp_global_printer, SP_ARG_PRINT,
282      N_("Print document(s) to specified output file (use '| program' for pipe)"),
283      N_("FILENAME")},
285     {"export-png", 'e',
286      POPT_ARG_STRING, &sp_export_png, SP_ARG_EXPORT_PNG,
287      N_("Export document to a PNG file"),
288      N_("FILENAME")},
290     {"export-dpi", 'd',
291      POPT_ARG_STRING, &sp_export_dpi, SP_ARG_EXPORT_DPI,
292      N_("The resolution used for exporting SVG into bitmap (default 90)"),
293      N_("DPI")},
295     {"export-area", 'a',
296      POPT_ARG_STRING, &sp_export_area, SP_ARG_EXPORT_AREA,
297      N_("Exported area in SVG user units (default is the canvas; 0,0 is lower-left corner)"),
298      N_("x0:y0:x1:y1")},
300     {"export-area-drawing", 'D',
301      POPT_ARG_NONE, &sp_export_area_drawing, SP_ARG_EXPORT_AREA_DRAWING,
302      N_("Exported area is the entire drawing (not canvas)"),
303      NULL},
305     {"export-area-canvas", 'C',
306      POPT_ARG_NONE, &sp_export_area_canvas, SP_ARG_EXPORT_AREA_CANVAS,
307      N_("Exported area is the entire canvas"),
308      NULL},
310     {"export-area-snap", 0,
311      POPT_ARG_NONE, &sp_export_area_snap, SP_ARG_EXPORT_AREA_SNAP,
312      N_("Snap the bitmap export area outwards to the nearest integer values (in SVG user units)"),
313      NULL},
315     {"export-width", 'w',
316      POPT_ARG_STRING, &sp_export_width, SP_ARG_EXPORT_WIDTH,
317      N_("The width of exported bitmap in pixels (overrides export-dpi)"),
318      N_("WIDTH")},
320     {"export-height", 'h',
321      POPT_ARG_STRING, &sp_export_height, SP_ARG_EXPORT_HEIGHT,
322      N_("The height of exported bitmap in pixels (overrides export-dpi)"),
323      N_("HEIGHT")},
325     {"export-id", 'i',
326      POPT_ARG_STRING, &sp_export_id, SP_ARG_EXPORT_ID,
327      N_("The ID of the object to export"),
328      N_("ID")},
330     {"export-id-only", 'j',
331      POPT_ARG_NONE, &sp_export_id_only, SP_ARG_EXPORT_ID_ONLY,
332      // TRANSLATORS: this means: "Only export the object whose id is given in --export-id".
333      //  See "man inkscape" for details.
334      N_("Export just the object with export-id, hide all others (only with export-id)"),
335      NULL},
337     {"export-use-hints", 't',
338      POPT_ARG_NONE, &sp_export_use_hints, SP_ARG_EXPORT_USE_HINTS,
339      N_("Use stored filename and DPI hints when exporting (only with export-id)"),
340      NULL},
342     {"export-background", 'b',
343      POPT_ARG_STRING, &sp_export_background, SP_ARG_EXPORT_BACKGROUND,
344      N_("Background color of exported bitmap (any SVG-supported color string)"),
345      N_("COLOR")},
347     {"export-background-opacity", 'y',
348      POPT_ARG_STRING, &sp_export_background_opacity, SP_ARG_EXPORT_BACKGROUND_OPACITY,
349      N_("Background opacity of exported bitmap (either 0.0 to 1.0, or 1 to 255)"),
350      N_("VALUE")},
352     {"export-plain-svg", 'l',
353      POPT_ARG_STRING, &sp_export_svg, SP_ARG_EXPORT_SVG,
354      N_("Export document to plain SVG file (no sodipodi or inkscape namespaces)"),
355      N_("FILENAME")},
357     {"export-ps", 'P',
358      POPT_ARG_STRING, &sp_export_ps, SP_ARG_EXPORT_PS,
359      N_("Export document to a PS file"),
360      N_("FILENAME")},
362     {"export-eps", 'E',
363      POPT_ARG_STRING, &sp_export_eps, SP_ARG_EXPORT_EPS,
364      N_("Export document to an EPS file"),
365      N_("FILENAME")},
367     {"export-pdf", 'A',
368      POPT_ARG_STRING, &sp_export_pdf, SP_ARG_EXPORT_PDF,
369      N_("Export document to a PDF file"),
370      N_("FILENAME")},
372 #ifdef WIN32
373     {"export-emf", 'M',
374      POPT_ARG_STRING, &sp_export_emf, SP_ARG_EXPORT_EMF,
375      N_("Export document to an Enhanced Metafile (EMF) File"),
376      N_("FILENAME")},
377 #endif //WIN32
379     {"export-text-to-path", 'T',
380      POPT_ARG_NONE, &sp_export_text_to_path, SP_ARG_EXPORT_TEXT_TO_PATH,
381      N_("Convert text object to paths on export (EPS)"),
382      NULL},
384     {"export-embed-fonts", 'F',
385      POPT_ARG_NONE, &sp_export_font, SP_ARG_EXPORT_FONT,
386      N_("Embed fonts on export (Type 1 only) (EPS)"),
387      NULL},
389     {"export-bbox-page", 'B',
390      POPT_ARG_NONE, &sp_export_bbox_page, SP_ARG_EXPORT_BBOX_PAGE,
391      N_("Export files with the bounding box set to the page size (EPS)"),
392      NULL},
394     {"query-x", 'X',
395      POPT_ARG_NONE, &sp_query_x, SP_ARG_QUERY_X,
396      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
397      N_("Query the X coordinate of the drawing or, if specified, of the object with --query-id"),
398      NULL},
400     {"query-y", 'Y',
401      POPT_ARG_NONE, &sp_query_y, SP_ARG_QUERY_Y,
402      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
403      N_("Query the Y coordinate of the drawing or, if specified, of the object with --query-id"),
404      NULL},
406     {"query-width", 'W',
407      POPT_ARG_NONE, &sp_query_width, SP_ARG_QUERY_WIDTH,
408      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
409      N_("Query the width of the drawing or, if specified, of the object with --query-id"),
410      NULL},
412     {"query-height", 'H',
413      POPT_ARG_NONE, &sp_query_height, SP_ARG_QUERY_HEIGHT,
414      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
415      N_("Query the height of the drawing or, if specified, of the object with --query-id"),
416      NULL},
418     {"query-all", 'S',
419      POPT_ARG_NONE, &sp_query_all, SP_ARG_QUERY_ALL,
420      N_("List id,x,y,w,h for all objects"),
421      NULL},
423     {"query-id", 'I',
424      POPT_ARG_STRING, &sp_query_id, SP_ARG_QUERY_ID,
425      N_("The ID of the object whose dimensions are queried"),
426      N_("ID")},
428     {"extension-directory", 'x',
429      POPT_ARG_NONE, NULL, SP_ARG_EXTENSIONDIR,
430      // TRANSLATORS: this option makes Inkscape print the name (path) of the extension directory
431      N_("Print out the extension directory and exit"),
432      NULL},
434     {"vacuum-defs", 0,
435      POPT_ARG_NONE, &sp_vacuum_defs, SP_ARG_VACUUM_DEFS,
436      N_("Remove unused definitions from the defs section(s) of the document"),
437      NULL},
439     {"verb-list", 0,
440      POPT_ARG_NONE, NULL, SP_ARG_VERB_LIST,
441      N_("List the IDs of all the verbs in Inkscape"),
442      NULL},
444     {"verb", 0,
445      POPT_ARG_STRING, NULL, SP_ARG_VERB,
446      N_("Verb to call when Inkscape opens."),
447      N_("VERB-ID")},
449     {"select", 0,
450      POPT_ARG_STRING, NULL, SP_ARG_SELECT,
451      N_("Object ID to select when Inkscape opens."),
452      N_("OBJECT-ID")},
454     {"shell", 0,
455      POPT_ARG_NONE, &sp_shell, SP_ARG_SHELL,
456      N_("Start Inkscape in interative shell mode."),
457      NULL},
459     POPT_AUTOHELP POPT_TABLEEND
460 };
462 static bool needToRecodeParams = true;
463 gchar * blankParam = g_strdup("");
467 #ifdef WIN32
469 /**
470  * Return the directory of the .exe that is currently running
471  */
472 static Glib::ustring _win32_getExePath()
474     char exeName[MAX_PATH+1];
475     GetModuleFileName(NULL, exeName, MAX_PATH);
476     char *slashPos = strrchr(exeName, '\\');
477     if (slashPos)
478         *slashPos = '\0';
479     Glib::ustring s = exeName;
480     return s;
483 /**
484  * Set up the PATH and PYTHONPATH environment variables on
485  * win32
486  */
487 static int _win32_set_inkscape_env(const Glib::ustring &exePath)
490     char *oldenv = getenv("PATH");
491     Glib::ustring tmp = "PATH=";
492     tmp += exePath;
493     tmp += ";";
494     tmp += exePath;
495     tmp += "\\python;";
496     tmp += exePath;
497     tmp += "\\python\\Scripts;";  // for uniconv.cmd
498     tmp += exePath;
499     tmp += "\\perl";
500     if(oldenv != NULL) {
501         tmp += ";";
502         tmp += oldenv;
503     }
504     _putenv(tmp.c_str());
506     oldenv = getenv("PYTHONPATH");
507     tmp = "PYTHONPATH=";
508     tmp += exePath;
509     tmp += "\\python;";
510     tmp += exePath;
511     tmp += "\\python\\Lib;";
512     tmp += exePath;
513     tmp += "\\python\\DLLs";
514     if(oldenv != NULL) {
515         tmp += ";";
516         tmp += oldenv;
517     }
518     _putenv(tmp.c_str());
520     return 0;
522 #endif
526 /**
527  * This is the classic main() entry point of the program, though on some
528  * architectures it might be called by something else.
529  */
530 int
531 main(int argc, char **argv)
533 #ifdef HAVE_FPSETMASK
534     /* This is inherited from Sodipodi code, where it was in #ifdef __FreeBSD__.  It's probably
535        safe to remove: the default mask is already 0 in C99, and in current FreeBSD according to
536        the fenv man page on www.freebsd.org, and in glibc according to (libc)FP Exceptions. */
537     fpsetmask(fpgetmask() & ~(FP_X_DZ | FP_X_INV));
538 #endif
540 #ifdef WIN32
541     /*
542       Set the current directory to the directory of the
543       executable.  This seems redundant, but is needed for
544       when inkscape.exe is executed from another directory.
545       We use relative paths on win32.
546       HKCR\svgfile\shell\open\command is a good example
547     */
548     Glib::ustring homedir = _win32_getExePath();
549     SetCurrentDirectory(homedir.c_str());
550     _win32_set_inkscape_env(homedir);
551     RegistryTool rt;
552     rt.setPathInfo();
553 #endif
555    /**
556     * Call bindtextdomain() for various machines's paths
557     */
558 #ifdef ENABLE_NLS
559 #ifdef WIN32
560     Glib::ustring localePath = homedir;
561     localePath += "\\";
562     localePath += PACKAGE_LOCALE_DIR;
563     bindtextdomain(GETTEXT_PACKAGE, localePath.c_str());
564 #else
565 #ifdef ENABLE_BINRELOC
566     bindtextdomain(GETTEXT_PACKAGE, BR_LOCALEDIR(""));
567 #else
568     bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
569 #endif
570 #endif
571     // Allow the user to override the locale directory by setting
572     // the environment variable INKSCAPE_LOCALEDIR.
573     char *inkscape_localedir = getenv("INKSCAPE_LOCALEDIR");
574     if (inkscape_localedir != NULL) {
575         bindtextdomain(GETTEXT_PACKAGE, inkscape_localedir);
576     }
577 #endif
579     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
581 #ifdef ENABLE_NLS
582     textdomain(GETTEXT_PACKAGE);
583 #endif
585     LIBXML_TEST_VERSION
587     Inkscape::GC::init();
589     Inkscape::Debug::Logger::init();
591     gboolean use_gui;
593 #ifndef WIN32
594     use_gui = (getenv("DISPLAY") != NULL);
595 #else
596     use_gui = TRUE;
597 #endif
598     /* Test whether with/without GUI is forced */
599     for (int i = 1; i < argc; i++) {
600         if (!strcmp(argv[i], "-z")
601             || !strcmp(argv[i], "--without-gui")
602             || !strcmp(argv[i], "-p")
603             || !strncmp(argv[i], "--print", 7)
604             || !strcmp(argv[i], "-e")
605             || !strncmp(argv[i], "--export-png", 12)
606             || !strcmp(argv[i], "-l")
607             || !strncmp(argv[i], "--export-plain-svg", 12)
608             || !strcmp(argv[i], "-i")
609             || !strncmp(argv[i], "--export-area-drawing", 21)
610             || !strcmp(argv[i], "-D")
611             || !strncmp(argv[i], "--export-area-canvas", 20)
612             || !strcmp(argv[i], "-C")
613             || !strncmp(argv[i], "--export-id", 12)
614             || !strcmp(argv[i], "-P")
615             || !strncmp(argv[i], "--export-ps", 11)
616             || !strcmp(argv[i], "-E")
617             || !strncmp(argv[i], "--export-eps", 12)
618             || !strcmp(argv[i], "-A")
619             || !strncmp(argv[i], "--export-pdf", 12)
620 #ifdef WIN32
621             || !strcmp(argv[i], "-M")
622             || !strncmp(argv[i], "--export-emf", 12)
623 #endif //WIN32
624             || !strcmp(argv[i], "-W")
625             || !strncmp(argv[i], "--query-width", 13)
626             || !strcmp(argv[i], "-H")
627             || !strncmp(argv[i], "--query-height", 14)
628             || !strcmp(argv[i], "-S")
629             || !strncmp(argv[i], "--query-all", 11)
630             || !strcmp(argv[i], "-X")
631             || !strncmp(argv[i], "--query-x", 13)
632             || !strcmp(argv[i], "-Y")
633             || !strncmp(argv[i], "--query-y", 14)
634             || !strcmp(argv[i], "--vacuum-defs")
635             || !strncmp(argv[i], "--shell", 7)
636            )
637         {
638             /* main_console handles any exports -- not the gui */
639             use_gui = FALSE;
640             break;
641         } else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "--with-gui")) {
642             use_gui = TRUE;
643             break;
644         }
645     }
647 #ifdef WIN32
648 #ifndef REPLACEARGS_ANSI
649     if ( PrintWin32::is_os_wide() )
650 #endif // REPLACEARGS_ANSI
651     {
652         // If the call fails, we'll need to convert charsets
653         needToRecodeParams = !replaceArgs( argc, argv );
654     }
655 #endif // WIN32
657     /// \todo  Should this be a static object (see inkscape.cpp)?
658     Inkscape::NSApplication::Application app(argc, argv, use_gui, sp_new_gui);
660     return app.run();
666 void fixupSingleFilename( gchar **orig, gchar **spare )
668     if ( orig && *orig && **orig ) {
669         GError *error = NULL;
670         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(*orig, -1, NULL, NULL, &error);
671         if ( newFileName )
672         {
673             *orig = newFileName;
674             if ( spare ) {
675                 *spare = newFileName;
676             }
677 //             g_message("Set a replacement fixup");
678         }
679     }
684 GSList *fixupFilenameEncoding( GSList* fl )
686     GSList *newFl = NULL;
687     while ( fl ) {
688         gchar *fn = static_cast<gchar*>(fl->data);
689         fl = g_slist_remove( fl, fl->data );
690         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(fn, -1, NULL, NULL, NULL);
691         if ( newFileName ) {
693             if ( 0 )
694             {
695                 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
696                 gchar *safeNewFn = Inkscape::IO::sanitizeString(newFileName);
697                 GtkWidget *w = gtk_message_dialog_new( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
698                                                        "Note: Converted '%s' to '%s'", safeFn, safeNewFn );
699                 gtk_dialog_run (GTK_DIALOG (w));
700                 gtk_widget_destroy (w);
701                 g_free(safeNewFn);
702                 g_free(safeFn);
703             }
705             g_free( fn );
706             fn = newFileName;
707             newFileName = 0;
708         }
709         else
710             if ( 0 )
711         {
712             gchar *safeFn = Inkscape::IO::sanitizeString(fn);
713             GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "Error: Unable to convert '%s'", safeFn );
714             gtk_dialog_run (GTK_DIALOG (w));
715             gtk_widget_destroy (w);
716             g_free(safeFn);
717         }
718         newFl = g_slist_append( newFl, fn );
719     }
720     return newFl;
723 int sp_common_main( int argc, char const **argv, GSList **flDest )
725     /// \todo fixme: Move these to some centralized location (Lauris)
726     sp_object_type_register("sodipodi:namedview", SP_TYPE_NAMEDVIEW);
727     sp_object_type_register("sodipodi:guide", SP_TYPE_GUIDE);
730     // temporarily switch gettext encoding to locale, so that help messages can be output properly
731     gchar const *charset;
732     g_get_charset(&charset);
734     bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
736     poptContext ctx = poptGetContext(NULL, argc, argv, options, 0);
737     poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
738     g_return_val_if_fail(ctx != NULL, 1);
740     /* Collect own arguments */
741     GSList *fl = sp_process_args(ctx);
742     poptFreeContext(ctx);
744     // now switch gettext back to UTF-8 (for GUI)
745     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
747     // Now let's see if the file list still holds up
748     if ( needToRecodeParams )
749     {
750         fl = fixupFilenameEncoding( fl );
751     }
753     // Check the globals for filename-fixup
754     if ( needToRecodeParams )
755     {
756         fixupSingleFilename( &sp_export_png, &sp_export_png_utf8 );
757         fixupSingleFilename( &sp_export_svg, &sp_export_svg_utf8 );
758         fixupSingleFilename( &sp_global_printer, &sp_global_printer_utf8 );
759     }
760     else
761     {
762         if ( sp_export_png )
763             sp_export_png_utf8 = g_strdup( sp_export_png );
764         if ( sp_export_svg )
765             sp_export_svg_utf8 = g_strdup( sp_export_svg );
766         if ( sp_global_printer )
767             sp_global_printer_utf8 = g_strdup( sp_global_printer );
768     }
770     // Return the list if wanted, else free it up.
771     if ( flDest ) {
772         *flDest = fl;
773         fl = 0;
774     } else {
775         while ( fl ) {
776             g_free( fl->data );
777             fl = g_slist_remove( fl, fl->data );
778         }
779     }
780     return 0;
783 static void
784 snooper(GdkEvent *event, gpointer /*data*/) {
785     if(inkscape_mapalt())  /* returns the map of the keyboard modifier to map to Alt, zero if no mapping */
786     {
787         GdkModifierType mapping=(GdkModifierType)inkscape_mapalt();
788         switch (event->type) {
789             case GDK_MOTION_NOTIFY:
790                 if(event->motion.state & mapping) {
791                     event->motion.state|=GDK_MOD1_MASK;
792                 }
793                 break;
794             case GDK_BUTTON_PRESS:
795                 if(event->button.state & mapping) {
796                     event->button.state|=GDK_MOD1_MASK;
797                 }
798                 break;
799              case GDK_KEY_PRESS:
800                  if(event->key.state & mapping) {
801                      event->key.state|=GDK_MOD1_MASK;
802                  }
803                  break;
804         default:
805             break;
806         }
807     }
808     gtk_main_do_event (event);
811 int
812 sp_main_gui(int argc, char const **argv)
814     Gtk::Main main_instance (&argc, const_cast<char ***>(&argv));
816     GSList *fl = NULL;
817     int retVal = sp_common_main( argc, argv, &fl );
818     g_return_val_if_fail(retVal == 0, 1);
820     inkscape_gtk_stock_init();
822     gdk_event_handler_set((GdkEventFunc)snooper, NULL, NULL);
824     Inkscape::Debug::log_display_config();
826     /* Set default icon */
827     gchar *filename = (gchar *) g_build_filename (INKSCAPE_APPICONDIR, "inkscape.png", NULL);
828     if (Inkscape::IO::file_test(filename, (GFileTest)(G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK))) {
829         gtk_window_set_default_icon_from_file(filename, NULL);
830     }
831     g_free (filename);
832     filename = 0;
834     gboolean create_new = TRUE;
836     /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
837     inkscape_application_init(argv[0], true);
839     while (fl) {
840         if (sp_file_open((gchar *)fl->data,NULL)) {
841             create_new=FALSE;
842         }
843         fl = g_slist_remove(fl, fl->data);
844     }
845     if (create_new) {
846         sp_file_new_default();
847     }
849     Glib::signal_idle().connect(sigc::ptr_fun(&Inkscape::CmdLineAction::idle));
850     main_instance.run();
852 #ifdef WIN32
853     //We might not need anything here
854     //sp_win32_finish(); <-- this is a NOP func
855 #endif
857     return 0;
860 /**
861  * Process file list
862  */
863 void sp_process_file_list(GSList *fl)
865     while (fl) {
866         const gchar *filename = (gchar *)fl->data;
867         SPDocument *doc = Inkscape::Extension::open(NULL, filename);
868         if (doc == NULL) {
869             doc = Inkscape::Extension::open(Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), filename);
870         }
871         if (doc == NULL) {
872             g_warning("Specified document %s cannot be opened (is it valid SVG file?)", filename);
873         } else {
874             if (sp_vacuum_defs) {
875                 vacuum_document(doc);
876             }
877             if (sp_vacuum_defs && !sp_export_svg) {
878                 // save under the name given in the command line
879                 sp_repr_save_file(doc->rdoc, filename, SP_SVG_NS_URI);
880             }
881             if (sp_global_printer) {
882                 sp_print_document_to_file(doc, sp_global_printer);
883             }
884             if (sp_export_png) {
885                 sp_do_export_png(doc);
886             }
887             if (sp_export_svg) {
888                 Inkscape::XML::Document *rdoc;
889                 Inkscape::XML::Node *repr;
890                 rdoc = sp_repr_document_new("svg:svg");
891                 repr = rdoc->root();
892                 repr = sp_document_root(doc)->updateRepr(rdoc, repr, SP_OBJECT_WRITE_BUILD);
893                 sp_repr_save_file(repr->document(), sp_export_svg, SP_SVG_NS_URI);
894             }
895             if (sp_export_ps) {
896                 do_export_ps(doc, sp_export_ps, "image/x-postscript");
897             }
898             if (sp_export_eps) {
899                 do_export_ps(doc, sp_export_eps, "image/x-e-postscript");
900             }
901             if (sp_export_pdf) {
902                 do_export_pdf(doc, sp_export_pdf, "application/pdf");
903                 }
904 #ifdef WIN32
905                 if (sp_export_emf) {
906                     do_export_emf(doc, sp_export_emf, "image/x-emf");
907                 }
908 #endif //WIN32
909             if (sp_query_all) {
910                 do_query_all (doc);
911             } else if (sp_query_width || sp_query_height) {
912                 do_query_dimension (doc, true, sp_query_width? NR::X : NR::Y, sp_query_id);
913             } else if (sp_query_x || sp_query_y) {
914                 do_query_dimension (doc, false, sp_query_x? NR::X : NR::Y, sp_query_id);
915             }
916         }
917         delete doc; /// \todo: Check the proper way to delete a SPDocument.
918         fl = g_slist_remove(fl, fl->data);
919     }
922 /**
923  * Run the application as an interactive shell, parsing command lines from stdin
924  * Returns -1 on error.
925  */
926 int sp_main_shell(char const* command_name)
928     int retval = 0;
930     const unsigned int buffer_size = 4096;
931     gchar *command_line = g_strnfill(buffer_size, 0);
932     g_strlcpy(command_line, command_name, buffer_size);
933     gsize offset = g_strlcat(command_line, " ", buffer_size);
934     gsize sizeLeft = buffer_size - offset;
935     gchar *useme = command_line + offset;
937     fprintf(stdout, "Inkscape %s interactive shell mode. Type 'quit' to quit.\n", INKSCAPE_VERSION);
938     fflush(stdout);
939     char* linedata = 0;
940     do {
941         fprintf(stdout, ">");
942         fflush(stdout);
943         if ((linedata = fgets(useme, sizeLeft, stdin))) {
944             size_t len = strlen(useme);
945             if ( (len >= sizeLeft - 1) || (useme[len - 1] != '\n') ) {
946                 fprintf(stdout, "ERROR: Command line too long\n");
947                 // Consume rest of line
948                 retval = -1; // If the while loop completes, this remains -1
949                 while (fgets(useme, sizeLeft, stdin) && retval) {
950                     len = strlen(command_line);
951                     if ( (len < buffer_size) && (command_line[len-1] == '\n') ) {
952                         retval = 0;
953                     }
954                 }
955             } else {
956                 useme[--len] = '\0';  // Strip newline
957                 if (useme[len - 1] == '\r') {
958                     useme[--len] = '\0';
959                 }
960                 if ( strcmp(useme, "quit") == 0 ) {
961                     // Time to quit
962                     fprintf(stdout, "done\n");
963                     fflush(stdout);
964                     linedata = 0; // mark for exit
965                 } else if ( len < 1 ) {
966                     // blank string. Do nothing.
967                 } else {
968                     GError* parseError = 0;
969                     gchar** argv = 0;
970                     gint argc = 0;
971                     if ( g_shell_parse_argv(useme, &argc, &argv, &parseError) ) {
972                         poptContext ctx = poptGetContext(NULL, argc, const_cast<const gchar**>(argv), options, 0);
973                         poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
974                         if ( ctx ) {
975                             GSList *fl = sp_process_args(ctx);
976                             sp_process_file_list(fl);
977                             poptFreeContext(ctx);
978                         } else {
979                             retval = 1; // not sure why. But this was the previous return value
980                         }
981                         resetCommandlineGlobals();
982                         g_strfreev(argv);
983                     } else {
984                         g_warning("problem parsing command-line");
985                     }
986                 }
987             }
988         } // if (linedata...
989     } while (linedata && (retval == 0));
991     g_free(command_line);
992     return retval;
995 int sp_main_console(int argc, char const **argv)
997     /* We are started in text mode */
999     /* Do this g_type_init(), so that we can use Xft/Freetype2 (Pango)
1000      * in a non-Gtk environment.  Used in libnrtype's
1001      * FontInstance.cpp and FontFactory.cpp.
1002      * http://mail.gnome.org/archives/gtk-list/2003-December/msg00063.html
1003      */
1004     g_type_init();
1005     char **argv2 = const_cast<char **>(argv);
1006     gtk_init_check( &argc, &argv2 );
1007     //setlocale(LC_ALL, "");
1009     GSList *fl = NULL;
1010     int retVal = sp_common_main( argc, argv, &fl );
1011     g_return_val_if_fail(retVal == 0, 1);
1013     if (fl == NULL && !sp_shell) {
1014         g_print("Nothing to do!\n");
1015         exit(0);
1016     }
1018     inkscape_application_init(argv[0], false);
1020     if (sp_shell) {
1021         sp_main_shell(argv[0]); // Run as interactive shell
1022     } else {
1023         sp_process_file_list(fl); // Normal command line invokation
1024     }
1025     inkscape_unref();
1027     return 0;
1030 static void
1031 do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id)
1033     SPObject *o = NULL;
1035     if (id) {
1036         o = doc->getObjectById(id);
1037         if (o) {
1038             if (!SP_IS_ITEM (o)) {
1039                 g_warning("Object with id=\"%s\" is not a visible item. Cannot query dimensions.", id);
1040                 return;
1041             }
1042         } else {
1043             g_warning("Object with id=\"%s\" is not found. Cannot query dimensions.", id);
1044             return;
1045         }
1046     } else {
1047         o = SP_DOCUMENT_ROOT(doc);
1048     }
1050     if (o) {
1051         sp_document_ensure_up_to_date (doc);
1052         SPItem *item = ((SPItem *) o);
1054         // "true" SVG bbox for scripting
1055         boost::optional<NR::Rect> area = item->getBounds(sp_item_i2doc_affine(item));
1056         if (area) {
1057             Inkscape::SVGOStringStream os;
1058             if (extent) {
1059                 os << area->extent(axis);
1060             } else {
1061                 os << area->min()[axis];
1062             }
1063             g_print ("%s", os.str().c_str());
1064         } else {
1065             g_print("0");
1066         }
1067     }
1070 static void
1071 do_query_all (SPDocument *doc)
1073     SPObject *o = NULL;
1075     o = SP_DOCUMENT_ROOT(doc);
1077     if (o) {
1078         sp_document_ensure_up_to_date (doc);
1079         do_query_all_recurse(o);
1080     }
1083 static void
1084 do_query_all_recurse (SPObject *o)
1086     SPItem *item = ((SPItem *) o);
1087     if (o->id && SP_IS_ITEM(item)) {
1088         boost::optional<NR::Rect> area = item->getBounds(sp_item_i2doc_affine(item));
1089         if (area) {
1090             Inkscape::SVGOStringStream os;
1091             os << o->id;
1092             os << "," << area->min()[NR::X];
1093             os << "," << area->min()[NR::Y];
1094             os << "," << area->extent(NR::X);
1095             os << "," << area->extent(NR::Y);
1096             g_print ("%s\n", os.str().c_str());
1097         }
1098     }
1100     SPObject *child = o->children;
1101     while (child) {
1102         do_query_all_recurse (child);
1103         child = child->next;
1104     }
1108 static void
1109 sp_do_export_png(SPDocument *doc)
1111     const gchar *filename = NULL;
1112     gdouble dpi = 0.0;
1114     if (sp_export_use_hints && (!sp_export_id && !sp_export_area_drawing)) {
1115         g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored.");
1116     }
1118     GSList *items = NULL;
1120     NRRect area;
1121     if (sp_export_id || sp_export_area_drawing) {
1123         SPObject *o = NULL;
1124         SPObject *o_area = NULL;
1125         if (sp_export_id && sp_export_area_drawing) {
1126             o = doc->getObjectById(sp_export_id);
1127             o_area = SP_DOCUMENT_ROOT (doc);
1128         } else if (sp_export_id) {
1129             o = doc->getObjectById(sp_export_id);
1130             o_area = o;
1131         } else if (sp_export_area_drawing) {
1132             o = SP_DOCUMENT_ROOT (doc);
1133             o_area = o;
1134         }
1136         if (o) {
1137             if (!SP_IS_ITEM (o)) {
1138                 g_warning("Object with id=\"%s\" is not a visible item. Nothing exported.", sp_export_id);
1139                 return;
1140             }
1142             items = g_slist_prepend (items, SP_ITEM(o));
1144             if (sp_export_id_only) {
1145                 g_print("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id);
1146             }
1148             if (sp_export_use_hints) {
1150                 // retrieve export filename hint
1151                 const gchar *fn_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-filename");
1152                 if (fn_hint) {
1153                     if (sp_export_png) {
1154                         g_warning ("Using export filename from the command line (--export-png). Filename hint %s is ignored.", fn_hint);
1155                         filename = sp_export_png;
1156                     } else {
1157                         filename = fn_hint;
1158                     }
1159                 } else {
1160                     g_warning ("Export filename hint not found for the object.");
1161                     filename = sp_export_png;
1162                 }
1164                 // retrieve export dpi hints
1165                 const gchar *dpi_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
1166                 if (dpi_hint) {
1167                     if (sp_export_dpi || sp_export_width || sp_export_height) {
1168                         g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint);
1169                     } else {
1170                         dpi = atof(dpi_hint);
1171                     }
1172                 } else {
1173                     g_warning ("Export DPI hint not found for the object.");
1174                 }
1176             }
1178             // write object bbox to area
1179             sp_document_ensure_up_to_date (doc);
1180             sp_item_invoke_bbox((SPItem *) o_area, &area, sp_item_i2r_affine((SPItem *) o_area), TRUE);
1181         } else {
1182             g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
1183             return;
1184         }
1185     }
1187     if (sp_export_area) {
1188         /* Try to parse area (given in SVG pixels) */
1189         if (!sscanf(sp_export_area, "%lg:%lg:%lg:%lg", &area.x0, &area.y0, &area.x1, &area.y1) == 4) {
1190             g_warning("Cannot parse export area '%s'; use 'x0:y0:x1:y1'. Nothing exported.", sp_export_area);
1191             return;
1192         }
1193         if ((area.x0 >= area.x1) || (area.y0 >= area.y1)) {
1194             g_warning("Export area '%s' has negative width or height. Nothing exported.", sp_export_area);
1195             return;
1196         }
1197     } else if (sp_export_area_canvas || !(sp_export_id || sp_export_area_drawing)) {
1198         /* Export the whole canvas */
1199         sp_document_ensure_up_to_date (doc);
1200         area.x0 = SP_ROOT(doc->root)->x.computed;
1201         area.y0 = SP_ROOT(doc->root)->y.computed;
1202         area.x1 = area.x0 + sp_document_width (doc);
1203         area.y1 = area.y0 + sp_document_height (doc);
1204     }
1206     // set filename and dpi from options, if not yet set from the hints
1207     if (!filename) {
1208         if (!sp_export_png) {
1209             g_warning ("No export filename given and no filename hint. Nothing exported.");
1210             return;
1211         }
1212         filename = sp_export_png;
1213     }
1215     if (sp_export_dpi && dpi == 0.0) {
1216         dpi = atof(sp_export_dpi);
1217         if ((dpi < 0.1) || (dpi > 10000.0)) {
1218             g_warning("DPI value %s out of range [0.1 - 10000.0]. Nothing exported.", sp_export_dpi);
1219             return;
1220         }
1221         g_print("DPI: %g\n", dpi);
1222     }
1224     if (sp_export_area_snap) {
1225         area.x0 = std::floor (area.x0);
1226         area.y0 = std::floor (area.y0);
1227         area.x1 = std::ceil (area.x1);
1228         area.y1 = std::ceil (area.y1);
1229     }
1231     // default dpi
1232     if (dpi == 0.0)
1233         dpi = PX_PER_IN;
1235     unsigned long int width = 0;
1236     unsigned long int height = 0;
1238     if (sp_export_width) {
1239         errno=0;
1240         width = strtoul(sp_export_width, NULL, 0);
1241         if ((width < 1) || (width > PNG_UINT_31_MAX) || (errno == ERANGE) ) {
1242             g_warning("Export width %lu out of range (1 - %lu). Nothing exported.", width, (unsigned long int)PNG_UINT_31_MAX);
1243             return;
1244         }
1245         dpi = (gdouble) width * PX_PER_IN / (area.x1 - area.x0);
1246     }
1248     if (sp_export_height) {
1249         errno=0;
1250         height = strtoul(sp_export_height, NULL, 0);
1251         if ((height < 1) || (height > PNG_UINT_31_MAX)) {
1252             g_warning("Export height %lu out of range (1 - %lu). Nothing exported.", height, (unsigned long int)PNG_UINT_31_MAX);
1253             return;
1254         }
1255         dpi = (gdouble) height * PX_PER_IN / (area.y1 - area.y0);
1256     }
1258     if (!sp_export_width) {
1259         width = (unsigned long int) ((area.x1 - area.x0) * dpi / PX_PER_IN + 0.5);
1260     }
1262     if (!sp_export_height) {
1263         height = (unsigned long int) ((area.y1 - area.y0) * dpi / PX_PER_IN + 0.5);
1264     }
1266     guint32 bgcolor = 0x00000000;
1267     if (sp_export_background) {
1268         // override the page color
1269         bgcolor = sp_svg_read_color(sp_export_background, 0xffffff00);
1270         bgcolor |= 0xff; // default is no opacity
1271     } else {
1272         // read from namedview
1273         Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
1274         if (nv && nv->attribute("pagecolor"))
1275             bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
1276         if (nv && nv->attribute("inkscape:pageopacity"))
1277             bgcolor |= SP_COLOR_F_TO_U(sp_repr_get_double_attribute (nv, "inkscape:pageopacity", 1.0));
1278     }
1280     if (sp_export_background_opacity) {
1281         // override opacity
1282         gfloat value;
1283         if (sp_svg_number_read_f (sp_export_background_opacity, &value)) {
1284             if (value > 1.0) {
1285                 value = CLAMP (value, 1.0f, 255.0f);
1286                 bgcolor &= (guint32) 0xffffff00;
1287                 bgcolor |= (guint32) floor(value);
1288             } else {
1289                 value = CLAMP (value, 0.0f, 1.0f);
1290                 bgcolor &= (guint32) 0xffffff00;
1291                 bgcolor |= SP_COLOR_F_TO_U(value);
1292             }
1293         }
1294     }
1296     g_print("Background RRGGBBAA: %08x\n", bgcolor);
1298     g_print("Area %g:%g:%g:%g exported to %lu x %lu pixels (%g dpi)\n", area.x0, area.y0, area.x1, area.y1, width, height, dpi);
1300     g_print("Bitmap saved as: %s\n", filename);
1302     if ((width >= 1) && (height >= 1) && (width <= PNG_UINT_31_MAX) && (height <= PNG_UINT_31_MAX)) {
1303         sp_export_png_file(doc, filename, area.x0, area.y0, area.x1, area.y1, width, height, dpi, dpi, bgcolor, NULL, NULL, true, sp_export_id_only ? items : NULL);
1304     } else {
1305         g_warning("Calculated bitmap dimensions %lu %lu are out of range (1 - %lu). Nothing exported.", width, height, (unsigned long int)PNG_UINT_31_MAX);
1306     }
1308     g_slist_free (items);
1312 /**
1313  *  Perform an export of either PS or EPS.
1314  *
1315  *  \param doc Document to export.
1316  *  \param uri URI to export to.
1317  *  \param mime MIME type to export as.
1318  */
1320 static void do_export_ps(SPDocument* doc, gchar const* uri, char const* mime)
1322     Inkscape::Extension::DB::OutputList o;
1323     Inkscape::Extension::db.get_output_list(o);
1324     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1325     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1326         i++;
1327     }
1329     if (i == o.end())
1330     {
1331         g_warning ("Could not find an extension to export to MIME type %s.", mime);
1332         return;
1333     }
1335     bool old_text_to_path = false;
1336     bool old_font_embedded = false;
1337     bool old_bbox_page = false;
1339     try {
1340         old_text_to_path = (*i)->get_param_bool("textToPath");
1341         (*i)->set_param_bool("textToPath", sp_export_text_to_path);
1342     }
1343     catch (...) {
1344         g_warning ("Could not set export-text-to-path option for this export.");
1345     }
1347     try {
1348         old_font_embedded = (*i)->get_param_bool("fontEmbedded");
1349         (*i)->set_param_bool("fontEmbedded", sp_export_font);
1350     }
1351     catch (...) {
1352         g_warning ("Could not set export-font option for this export.");
1353     }
1355     try {
1356         old_bbox_page = (*i)->get_param_bool("pageBoundingBox");
1357         (*i)->set_param_bool("pageBoundingBox", sp_export_bbox_page);
1358     }
1359     catch (...) {
1360         g_warning ("Could not set export-bbox-page option for this export.");
1361     }
1363     (*i)->save(doc, uri);
1365     try {
1366         (*i)->set_param_bool("textToPath", old_text_to_path);
1367         (*i)->set_param_bool("fontEmbedded", old_font_embedded);
1368         (*i)->set_param_bool("pageBoundingBox", old_bbox_page);
1369     }
1370     catch (...) {
1372     }
1375 /**
1376  *  Perform a PDF export
1377  *
1378  *  \param doc Document to export.
1379  *  \param uri URI to export to.
1380  *  \param mime MIME type to export as.
1381  */
1383 static void do_export_pdf(SPDocument* doc, gchar const* uri, char const* mime)
1385     Inkscape::Extension::DB::OutputList o;
1386     Inkscape::Extension::db.get_output_list(o);
1387     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1388     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1389         i++;
1390     }
1392     if (i == o.end())
1393     {
1394         g_warning ("Could not find an extension to export to MIME type %s.", mime);
1395         return;
1396     }
1398     if (sp_export_id) {
1399         SPObject *o = doc->getObjectById(sp_export_id);
1400         if (o == NULL) {
1401             g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
1402             return;
1403         }
1404         (*i)->set_param_string ("exportId", sp_export_id);
1405     } else {
1406         (*i)->set_param_string ("exportId", "");
1407     }
1409     if (sp_export_area_drawing) {
1410         (*i)->set_param_bool ("exportDrawing", TRUE);
1411     } else {
1412         (*i)->set_param_bool ("exportDrawing", FALSE);
1413     }
1415     if (sp_export_area_canvas) {
1416         (*i)->set_param_bool ("exportCanvas", TRUE);
1417     } else {
1418         (*i)->set_param_bool ("exportCanvas", FALSE);
1419     }
1421     if (sp_export_text_to_path) {
1422         (*i)->set_param_bool("textToPath", TRUE);
1423     } else {
1424         (*i)->set_param_bool("textToPath", FALSE);
1425     }
1427     (*i)->save(doc, uri);
1430 #ifdef WIN32
1431 /**
1432  *  Export a document to EMF
1433  *
1434  *  \param doc Document to export.
1435  *  \param uri URI to export to.
1436  *  \param mime MIME type to export as (should be "image/x-emf")
1437  */
1439 static void do_export_emf(SPDocument* doc, gchar const* uri, char const* mime)
1441     Inkscape::Extension::DB::OutputList o;
1442     Inkscape::Extension::db.get_output_list(o);
1443     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1444     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1445         i++;
1446     }
1448     if (i == o.end())
1449     {
1450         g_warning ("Could not find an extension to export to MIME type %s.", mime);
1451         return;
1452     }
1454     (*i)->save(doc, uri);
1456 #endif //WIN32
1458 #ifdef WIN32
1459 bool replaceArgs( int& argc, char**& argv )
1461     bool worked = false;
1463 #ifdef REPLACEARGS_DEBUG
1464     MessageBoxA( NULL, "GetCommandLineW() getting called", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1465 #endif // REPLACEARGS_DEBUG
1467     wchar_t* line = GetCommandLineW();
1468     if ( line )
1469     {
1470 #ifdef REPLACEARGS_DEBUG
1471         {
1472             gchar* utf8Line = g_utf16_to_utf8( (gunichar2*)line, -1, NULL, NULL, NULL );
1473             if ( utf8Line )
1474             {
1475                 gchar *safe = Inkscape::IO::sanitizeString(utf8Line);
1476                 {
1477                     char tmp[strlen(safe) + 32];
1478                     snprintf( tmp, sizeof(tmp), "GetCommandLineW() = '%s'", safe );
1479                     MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1480                 }
1481             }
1482         }
1483 #endif // REPLACEARGS_DEBUG
1485         int numArgs = 0;
1486         wchar_t** parsed = CommandLineToArgvW( line, &numArgs );
1488 #ifdef REPLACEARGS_ANSI
1489 // test code for trying things on Win95/98/ME
1490         if ( !parsed )
1491         {
1492 #ifdef REPLACEARGS_DEBUG
1493             MessageBoxA( NULL, "Unable to process command-line. Faking it", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1494 #endif // REPLACEARGS_DEBUG
1495             int lineLen = wcslen(line) + 1;
1496             wchar_t* lineDup = new wchar_t[lineLen];
1497             wcsncpy( lineDup, line, lineLen );
1499             int pos = 0;
1500             bool inQuotes = false;
1501             bool inWhitespace = true;
1502             std::vector<int> places;
1503             while ( lineDup[pos] )
1504             {
1505                 if ( inQuotes )
1506                 {
1507                     if ( lineDup[pos] == L'"' )
1508                     {
1509                         inQuotes = false;
1510                     }
1511                 }
1512                 else if ( lineDup[pos] == L'"' )
1513                 {
1514                     inQuotes = true;
1515                     inWhitespace = false;
1516                     places.push_back(pos);
1517                 }
1518                 else if ( lineDup[pos] == L' ' || lineDup[pos] == L'\t' )
1519                 {
1520                     if ( !inWhitespace )
1521                     {
1522                         inWhitespace = true;
1523                         lineDup[pos] = 0;
1524                     }
1525                 }
1526                 else if ( inWhitespace && (lineDup[pos] != L' ' && lineDup[pos] != L'\t') )
1527                 {
1528                     inWhitespace = false;
1529                     places.push_back(pos);
1530                 }
1531                 else
1532                 {
1533                     // consume
1534                 }
1535                 pos++;
1536             }
1537 #ifdef REPLACEARGS_DEBUG
1538             {
1539                 char tmp[256];
1540                 snprintf( tmp, sizeof(tmp), "Counted %d args", places.size() );
1541                 MessageBoxA( NULL, tmp, "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1542             }
1543 #endif // REPLACEARGS_DEBUG
1545             wchar_t** block = new wchar_t*[places.size()];
1546             int i = 0;
1547             for ( std::vector<int>::iterator it = places.begin(); it != places.end(); it++ )
1548             {
1549                 block[i++] = &lineDup[*it];
1550             }
1551             parsed = block;
1552             numArgs = places.size();
1553         }
1554 #endif // REPLACEARGS_ANSI
1556         if ( parsed )
1557         {
1558             std::vector<wchar_t*>expandedArgs;
1559             if ( numArgs > 0 )
1560             {
1561                 expandedArgs.push_back( parsed[0] );
1562             }
1564             for ( int i1 = 1; i1 < numArgs; i1++ )
1565             {
1566                 bool wildcarded = (wcschr(parsed[i1], L'?') != NULL) || (wcschr(parsed[i1], L'*') != NULL);
1567                 wildcarded &= parsed[i1][0] != L'"';
1568                 wildcarded &= parsed[i1][0] != L'-';
1569                 if ( wildcarded )
1570                 {
1571 #ifdef REPLACEARGS_ANSI
1572                     WIN32_FIND_DATAA data;
1573 #else
1574                     WIN32_FIND_DATAW data;
1575 #endif // REPLACEARGS_ANSI
1577                     memset((void *)&data, 0, sizeof(data));
1579                     int baseLen = wcslen(parsed[i1]) + 2;
1580                     wchar_t* base = new wchar_t[baseLen];
1581                     wcsncpy( base, parsed[i1], baseLen );
1582                     wchar_t* last = wcsrchr( base, L'\\' );
1583                     if ( last )
1584                     {
1585                         last[1] = 0;
1586                     }
1587                     else
1588                     {
1589                         base[0] = 0;
1590                     }
1591                     baseLen = wcslen( base );
1593 #ifdef REPLACEARGS_ANSI
1594                     char target[MAX_PATH];
1595                     if ( WideCharToMultiByte( CP_ACP, 0, parsed[i1], -1, target, sizeof(target), NULL, NULL) )
1596                     {
1597                         HANDLE hf = FindFirstFileA( target, &data );
1598 #else
1599                         HANDLE hf = FindFirstFileW( parsed[i1], &data );
1600 #endif // REPLACEARGS_ANSI
1601                         if ( hf != INVALID_HANDLE_VALUE )
1602                         {
1603                             BOOL found = TRUE;
1604                             do
1605                             {
1606 #ifdef REPLACEARGS_ANSI
1607                                 int howMany = MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, NULL, 0 );
1608                                 if ( howMany > 0 )
1609                                 {
1610                                     howMany += baseLen;
1611                                     wchar_t* tmp = new wchar_t[howMany + 1];
1612                                     wcsncpy( tmp, base, howMany + 1 );
1613                                     MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, tmp + baseLen, howMany + 1 - baseLen );
1614                                     expandedArgs.push_back( tmp );
1615                                     found = FindNextFileA( hf, &data );
1616                                 }
1617 #else
1618                                 int howMany = wcslen(data.cFileName) + baseLen;
1619                                 wchar_t* tmp = new wchar_t[howMany + 1];
1620                                 wcsncpy( tmp, base, howMany + 1 );
1621                                 wcsncat( tmp, data.cFileName, howMany + 1 );
1622                                 expandedArgs.push_back( tmp );
1623                                 found = FindNextFileW( hf, &data );
1624 #endif // REPLACEARGS_ANSI
1625                             } while ( found );
1627                             FindClose( hf );
1628                         }
1629                         else
1630                         {
1631                             expandedArgs.push_back( parsed[i1] );
1632                         }
1633 #ifdef REPLACEARGS_ANSI
1634                     }
1635 #endif // REPLACEARGS_ANSI
1637                     delete[] base;
1638                 }
1639                 else
1640                 {
1641                     expandedArgs.push_back( parsed[i1] );
1642                 }
1643             }
1645             {
1646                 wchar_t** block = new wchar_t*[expandedArgs.size()];
1647                 int iz = 0;
1648                 for ( std::vector<wchar_t*>::iterator it = expandedArgs.begin(); it != expandedArgs.end(); it++ )
1649                 {
1650                     block[iz++] = *it;
1651                 }
1652                 parsed = block;
1653                 numArgs = expandedArgs.size();
1654             }
1656             std::vector<gchar*> newArgs;
1657             for ( int i = 0; i < numArgs; i++ )
1658             {
1659                 gchar* replacement = g_utf16_to_utf8( (gunichar2*)parsed[i], -1, NULL, NULL, NULL );
1660                 if ( replacement )
1661                 {
1662 #ifdef REPLACEARGS_DEBUG
1663                     gchar *safe2 = Inkscape::IO::sanitizeString(replacement);
1665                     if ( safe2 )
1666                     {
1667                         {
1668                             char tmp[1024];
1669                             snprintf( tmp, sizeof(tmp), "    [%2d] = '%s'", i, safe2 );
1670                             MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1671                         }
1672                         g_free( safe2 );
1673                     }
1674 #endif // REPLACEARGS_DEBUG
1676                     newArgs.push_back( replacement );
1677                 }
1678                 else
1679                 {
1680                     newArgs.push_back( blankParam );
1681                 }
1682             }
1684             // Now push our munged params to be the new argv and argc
1685             {
1686                 char** block = new char*[newArgs.size()];
1687                 int iz = 0;
1688                 for ( std::vector<char*>::iterator it = newArgs.begin(); it != newArgs.end(); it++ )
1689                 {
1690                     block[iz++] = *it;
1691                 }
1692                 argv = block;
1693                 argc = newArgs.size();
1694                 worked = true;
1695             }
1696         }
1697 #ifdef REPLACEARGS_DEBUG
1698         else
1699         {
1700             MessageBoxA( NULL, "Unable to process command-line", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1701         }
1702 #endif // REPLACEARGS_DEBUG
1703     }
1704 #ifdef REPLACEARGS_DEBUG
1705     else
1706     {
1707         {
1708             MessageBoxA( NULL,  "Unable to fetch result from GetCommandLineW()", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1709         }
1711         char* line2 = GetCommandLineA();
1712         if ( line2 )
1713         {
1714             gchar *safe = Inkscape::IO::sanitizeString(line2);
1715             {
1716                 {
1717                     char tmp[strlen(safe) + 32];
1718                     snprintf( tmp, sizeof(tmp), "GetCommandLineA() = '%s'", safe );
1719                     MessageBoxA( NULL, tmp, "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1720                 }
1721             }
1722         }
1723         else
1724         {
1725             MessageBoxA( NULL, "Unable to fetch result from GetCommandLineA()", "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1726         }
1727     }
1728 #endif // REPLACEARGS_DEBUG
1730     return worked;
1732 #endif // WIN32
1734 static GSList *
1735 sp_process_args(poptContext ctx)
1737     GSList *fl = NULL;
1739     gint a;
1740     while ((a = poptGetNextOpt(ctx)) >= 0) {
1741         switch (a) {
1742             case SP_ARG_FILE: {
1743                 gchar const *fn = poptGetOptArg(ctx);
1744                 if (fn != NULL) {
1745                     fl = g_slist_append(fl, g_strdup(fn));
1746                 }
1747                 break;
1748             }
1749             case SP_ARG_VERSION: {
1750                 printf("Inkscape %s (%s)\n", INKSCAPE_VERSION, __DATE__);
1751                 exit(0);
1752                 break;
1753             }
1754             case SP_ARG_EXTENSIONDIR: {
1755                 printf("%s\n", INKSCAPE_EXTENSIONDIR);
1756                 exit(0);
1757                 break;
1758             }
1759             case SP_ARG_VERB_LIST: {
1760                 // This really shouldn't go here, we should init the app.
1761                 // But, since we're just exiting in this path, there is
1762                 // no harm, and this is really a better place to put
1763                 // everything else.
1764                 Inkscape::Extension::init();
1765                 Inkscape::Verb::list();
1766                 exit(0);
1767                 break;
1768             }
1769             case SP_ARG_VERB:
1770             case SP_ARG_SELECT: {
1771                 gchar const *arg = poptGetOptArg(ctx);
1772                 if (arg != NULL) {
1773                     // printf("Adding in: %s\n", arg);
1774                     new Inkscape::CmdLineAction((a == SP_ARG_VERB), arg);
1775                 }
1776                 break;
1777             }
1778             default: {
1779                 break;
1780             }
1781         }
1782     }
1784     gchar const ** const args = poptGetArgs(ctx);
1785     if (args != NULL) {
1786         for (unsigned i = 0; args[i] != NULL; i++) {
1787             fl = g_slist_append(fl, g_strdup(args[i]));
1788         }
1789     }
1791     return fl;
1795 /*
1796   Local Variables:
1797   mode:c++
1798   c-file-style:"stroustrup"
1799   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1800   indent-tabs-mode:nil
1801   fill-column:99
1802   End:
1803 */
1804 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :