Code

Whitespace cleanup
[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_VERSION,
155     SP_ARG_VACUUM_DEFS,
156     SP_ARG_VERB_LIST,
157     SP_ARG_VERB,
158     SP_ARG_SELECT,
159     SP_ARG_LAST
160 };
162 int sp_main_gui(int argc, char const **argv);
163 int sp_main_console(int argc, char const **argv);
164 static void sp_do_export_png(SPDocument *doc);
165 static void do_export_ps(SPDocument* doc, gchar const* uri, char const *mime);
166 static void do_export_pdf(SPDocument* doc, gchar const* uri, char const *mime);
167 #ifdef WIN32
168 static void do_export_emf(SPDocument* doc, gchar const* uri, char const *mime);
169 #endif //WIN32
170 static void do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id);
171 static void do_query_all (SPDocument *doc);
172 static void do_query_all_recurse (SPObject *o);
174 static gchar *sp_global_printer = NULL;
175 static gchar *sp_export_png = NULL;
176 static gchar *sp_export_dpi = NULL;
177 static gchar *sp_export_area = NULL;
178 static gboolean sp_export_area_drawing = FALSE;
179 static gboolean sp_export_area_canvas = FALSE;
180 static gchar *sp_export_width = NULL;
181 static gchar *sp_export_height = NULL;
182 static gchar *sp_export_id = NULL;
183 static gchar *sp_export_background = NULL;
184 static gchar *sp_export_background_opacity = NULL;
185 static gboolean sp_export_area_snap = FALSE;
186 static gboolean sp_export_use_hints = FALSE;
187 static gboolean sp_export_id_only = FALSE;
188 static gchar *sp_export_svg = NULL;
189 static gchar *sp_export_ps = NULL;
190 static gchar *sp_export_eps = NULL;
191 static gchar *sp_export_pdf = NULL;
192 #ifdef WIN32
193 static gchar *sp_export_emf = NULL;
194 #endif //WIN32
195 static gboolean sp_export_text_to_path = FALSE;
196 static gboolean sp_export_font = FALSE;
197 static gboolean sp_export_bbox_page = FALSE;
198 static gboolean sp_query_x = FALSE;
199 static gboolean sp_query_y = FALSE;
200 static gboolean sp_query_width = FALSE;
201 static gboolean sp_query_height = FALSE;
202 static gboolean sp_query_all = FALSE;
203 static gchar *sp_query_id = NULL;
204 static int sp_new_gui = FALSE;
205 static gboolean sp_vacuum_defs = FALSE;
207 static gchar *sp_export_png_utf8 = NULL;
208 static gchar *sp_export_svg_utf8 = NULL;
209 static gchar *sp_global_printer_utf8 = NULL;
211 #ifdef WIN32
212 static bool replaceArgs( int& argc, char**& argv );
213 #endif
214 static GSList *sp_process_args(poptContext ctx);
215 struct poptOption options[] = {
216     {"version", 'V',
217      POPT_ARG_NONE, NULL, SP_ARG_VERSION,
218      N_("Print the Inkscape version number"),
219      NULL},
221     {"without-gui", 'z',
222      POPT_ARG_NONE, NULL, SP_ARG_NOGUI,
223      N_("Do not use X server (only process files from console)"),
224      NULL},
226     {"with-gui", 'g',
227      POPT_ARG_NONE, NULL, SP_ARG_GUI,
228      N_("Try to use X server (even if $DISPLAY is not set)"),
229      NULL},
231     {"file", 'f',
232      POPT_ARG_STRING, NULL, SP_ARG_FILE,
233      N_("Open specified document(s) (option string may be excluded)"),
234      N_("FILENAME")},
236     {"print", 'p',
237      POPT_ARG_STRING, &sp_global_printer, SP_ARG_PRINT,
238      N_("Print document(s) to specified output file (use '| program' for pipe)"),
239      N_("FILENAME")},
241     {"export-png", 'e',
242      POPT_ARG_STRING, &sp_export_png, SP_ARG_EXPORT_PNG,
243      N_("Export document to a PNG file"),
244      N_("FILENAME")},
246     {"export-dpi", 'd',
247      POPT_ARG_STRING, &sp_export_dpi, SP_ARG_EXPORT_DPI,
248      N_("The resolution used for exporting SVG into bitmap (default 90)"),
249      N_("DPI")},
251     {"export-area", 'a',
252      POPT_ARG_STRING, &sp_export_area, SP_ARG_EXPORT_AREA,
253      N_("Exported area in SVG user units (default is the canvas; 0,0 is lower-left corner)"),
254      N_("x0:y0:x1:y1")},
256     {"export-area-drawing", 'D',
257      POPT_ARG_NONE, &sp_export_area_drawing, SP_ARG_EXPORT_AREA_DRAWING,
258      N_("Exported area is the entire drawing (not canvas)"),
259      NULL},
261     {"export-area-canvas", 'C',
262      POPT_ARG_NONE, &sp_export_area_canvas, SP_ARG_EXPORT_AREA_CANVAS,
263      N_("Exported area is the entire canvas"),
264      NULL},
266     {"export-area-snap", 0,
267      POPT_ARG_NONE, &sp_export_area_snap, SP_ARG_EXPORT_AREA_SNAP,
268      N_("Snap the bitmap export area outwards to the nearest integer values (in SVG user units)"),
269      NULL},
271     {"export-width", 'w',
272      POPT_ARG_STRING, &sp_export_width, SP_ARG_EXPORT_WIDTH,
273      N_("The width of exported bitmap in pixels (overrides export-dpi)"),
274      N_("WIDTH")},
276     {"export-height", 'h',
277      POPT_ARG_STRING, &sp_export_height, SP_ARG_EXPORT_HEIGHT,
278      N_("The height of exported bitmap in pixels (overrides export-dpi)"),
279      N_("HEIGHT")},
281     {"export-id", 'i',
282      POPT_ARG_STRING, &sp_export_id, SP_ARG_EXPORT_ID,
283      N_("The ID of the object to export"),
284      N_("ID")},
286     {"export-id-only", 'j',
287      POPT_ARG_NONE, &sp_export_id_only, SP_ARG_EXPORT_ID_ONLY,
288      // TRANSLATORS: this means: "Only export the object whose id is given in --export-id".
289      //  See "man inkscape" for details.
290      N_("Export just the object with export-id, hide all others (only with export-id)"),
291      NULL},
293     {"export-use-hints", 't',
294      POPT_ARG_NONE, &sp_export_use_hints, SP_ARG_EXPORT_USE_HINTS,
295      N_("Use stored filename and DPI hints when exporting (only with export-id)"),
296      NULL},
298     {"export-background", 'b',
299      POPT_ARG_STRING, &sp_export_background, SP_ARG_EXPORT_BACKGROUND,
300      N_("Background color of exported bitmap (any SVG-supported color string)"),
301      N_("COLOR")},
303     {"export-background-opacity", 'y',
304      POPT_ARG_STRING, &sp_export_background_opacity, SP_ARG_EXPORT_BACKGROUND_OPACITY,
305      N_("Background opacity of exported bitmap (either 0.0 to 1.0, or 1 to 255)"),
306      N_("VALUE")},
308     {"export-plain-svg", 'l',
309      POPT_ARG_STRING, &sp_export_svg, SP_ARG_EXPORT_SVG,
310      N_("Export document to plain SVG file (no sodipodi or inkscape namespaces)"),
311      N_("FILENAME")},
313     {"export-ps", 'P',
314      POPT_ARG_STRING, &sp_export_ps, SP_ARG_EXPORT_PS,
315      N_("Export document to a PS file"),
316      N_("FILENAME")},
318     {"export-eps", 'E',
319      POPT_ARG_STRING, &sp_export_eps, SP_ARG_EXPORT_EPS,
320      N_("Export document to an EPS file"),
321      N_("FILENAME")},
323     {"export-pdf", 'A',
324      POPT_ARG_STRING, &sp_export_pdf, SP_ARG_EXPORT_PDF,
325      N_("Export document to a PDF file"),
326      N_("FILENAME")},
328 #ifdef WIN32
329     {"export-emf", 'M',
330      POPT_ARG_STRING, &sp_export_emf, SP_ARG_EXPORT_EMF,
331      N_("Export document to an Enhanced Metafile (EMF) File"),
332      N_("FILENAME")},
333 #endif //WIN32
335     {"export-text-to-path", 'T',
336      POPT_ARG_NONE, &sp_export_text_to_path, SP_ARG_EXPORT_TEXT_TO_PATH,
337      N_("Convert text object to paths on export (EPS)"),
338      NULL},
340     {"export-embed-fonts", 'F',
341      POPT_ARG_NONE, &sp_export_font, SP_ARG_EXPORT_FONT,
342      N_("Embed fonts on export (Type 1 only) (EPS)"),
343      NULL},
345     {"export-bbox-page", 'B',
346      POPT_ARG_NONE, &sp_export_bbox_page, SP_ARG_EXPORT_BBOX_PAGE,
347      N_("Export files with the bounding box set to the page size (EPS)"),
348      NULL},
350     {"query-x", 'X',
351      POPT_ARG_NONE, &sp_query_x, SP_ARG_QUERY_X,
352      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
353      N_("Query the X coordinate of the drawing or, if specified, of the object with --query-id"),
354      NULL},
356     {"query-y", 'Y',
357      POPT_ARG_NONE, &sp_query_y, SP_ARG_QUERY_Y,
358      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
359      N_("Query the Y coordinate of the drawing or, if specified, of the object with --query-id"),
360      NULL},
362     {"query-width", 'W',
363      POPT_ARG_NONE, &sp_query_width, SP_ARG_QUERY_WIDTH,
364      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
365      N_("Query the width of the drawing or, if specified, of the object with --query-id"),
366      NULL},
368     {"query-height", 'H',
369      POPT_ARG_NONE, &sp_query_height, SP_ARG_QUERY_HEIGHT,
370      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
371      N_("Query the height of the drawing or, if specified, of the object with --query-id"),
372      NULL},
374     {"query-all", 'S',
375      POPT_ARG_NONE, &sp_query_all, SP_ARG_QUERY_ALL,
376      N_("List id,x,y,w,h for all objects"),
377      NULL},
379     {"query-id", 'I',
380      POPT_ARG_STRING, &sp_query_id, SP_ARG_QUERY_ID,
381      N_("The ID of the object whose dimensions are queried"),
382      N_("ID")},
384     {"extension-directory", 'x',
385      POPT_ARG_NONE, NULL, SP_ARG_EXTENSIONDIR,
386      // TRANSLATORS: this option makes Inkscape print the name (path) of the extension directory
387      N_("Print out the extension directory and exit"),
388      NULL},
390     {"vacuum-defs", 0,
391      POPT_ARG_NONE, &sp_vacuum_defs, SP_ARG_VACUUM_DEFS,
392      N_("Remove unused definitions from the defs section(s) of the document"),
393      NULL},
395     {"verb-list", 0,
396      POPT_ARG_NONE, NULL, SP_ARG_VERB_LIST,
397      N_("List the IDs of all the verbs in Inkscape"),
398      NULL},
400     {"verb", 0,
401      POPT_ARG_STRING, NULL, SP_ARG_VERB,
402      N_("Verb to call when Inkscape opens."),
403      N_("VERB-ID")},
405     {"select", 0,
406      POPT_ARG_STRING, NULL, SP_ARG_SELECT,
407      N_("Object ID to select when Inkscape opens."),
408      N_("OBJECT-ID")},
410     POPT_AUTOHELP POPT_TABLEEND
411 };
413 static bool needToRecodeParams = true;
414 gchar * blankParam = g_strdup("");
418 #ifdef WIN32
420 /**
421  * Return the directory of the .exe that is currently running
422  */
423 static Glib::ustring _win32_getExePath()
425     char exeName[MAX_PATH+1];
426     GetModuleFileName(NULL, exeName, MAX_PATH);
427     char *slashPos = strrchr(exeName, '\\');
428     if (slashPos)
429         *slashPos = '\0';
430     Glib::ustring s = exeName;
431     return s;
434 /**
435  * Set up the PATH and PYTHONPATH environment variables on
436  * win32
437  */
438 static int _win32_set_inkscape_env(const Glib::ustring &exePath)
441     char *oldenv = getenv("PATH");
442     Glib::ustring tmp = "PATH=";
443     tmp += exePath;
444     tmp += ";";
445     tmp += exePath;
446     tmp += "\\python;";
447     tmp += exePath;
448     tmp += "\\python\\Scripts;";  // for uniconv.cmd
449     tmp += exePath;
450     tmp += "\\perl";
451     if(oldenv != NULL) {
452         tmp += ";";
453         tmp += oldenv;
454     }
455     _putenv(tmp.c_str());
457     oldenv = getenv("PYTHONPATH");
458     tmp = "PYTHONPATH=";
459     tmp += exePath;
460     tmp += "\\python;";
461     tmp += exePath;
462     tmp += "\\python\\Lib;";
463     tmp += exePath;
464     tmp += "\\python\\DLLs";
465     if(oldenv != NULL) {
466         tmp += ";";
467         tmp += oldenv;
468     }
469     _putenv(tmp.c_str());
471     return 0;
473 #endif
477 /**
478  * This is the classic main() entry point of the program, though on some
479  * architectures it might be called by something else.
480  */
481 int
482 main(int argc, char **argv)
484 #ifdef HAVE_FPSETMASK
485     /* This is inherited from Sodipodi code, where it was in #ifdef __FreeBSD__.  It's probably
486        safe to remove: the default mask is already 0 in C99, and in current FreeBSD according to
487        the fenv man page on www.freebsd.org, and in glibc according to (libc)FP Exceptions. */
488     fpsetmask(fpgetmask() & ~(FP_X_DZ | FP_X_INV));
489 #endif
491 #ifdef WIN32
492     /*
493       Set the current directory to the directory of the
494       executable.  This seems redundant, but is needed for
495       when inkscape.exe is executed from another directory.
496       We use relative paths on win32.
497       HKCR\svgfile\shell\open\command is a good example
498     */
499     Glib::ustring homedir = _win32_getExePath();
500     SetCurrentDirectory(homedir.c_str());
501     _win32_set_inkscape_env(homedir);
502     RegistryTool rt;
503     rt.setPathInfo();
504 #endif
506    /**
507     * Call bindtextdomain() for various machines's paths
508     */
509 #ifdef ENABLE_NLS
510 #ifdef WIN32
511     Glib::ustring localePath = homedir;
512         localePath += "\\";
513         localePath += PACKAGE_LOCALE_DIR;
514     bindtextdomain(GETTEXT_PACKAGE, localePath.c_str());
515 #else
516 #ifdef ENABLE_BINRELOC
517     bindtextdomain(GETTEXT_PACKAGE, BR_LOCALEDIR(""));
518 #else
519     bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
520 #endif
521 #endif
522     // Allow the user to override the locale directory by setting
523     // the environment variable INKSCAPE_LOCALEDIR.
524     char *inkscape_localedir = getenv("INKSCAPE_LOCALEDIR");
525     if (inkscape_localedir != NULL) {
526         bindtextdomain(GETTEXT_PACKAGE, inkscape_localedir);
527     }
528 #endif
530     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
532 #ifdef ENABLE_NLS
533     textdomain(GETTEXT_PACKAGE);
534 #endif
536     LIBXML_TEST_VERSION
538     Inkscape::GC::init();
540     Inkscape::Debug::Logger::init();
542     gboolean use_gui;
544 #ifndef WIN32
545     use_gui = (getenv("DISPLAY") != NULL);
546 #else
547     use_gui = TRUE;
548 #endif
549     /* Test whether with/without GUI is forced */
550     for (int i = 1; i < argc; i++) {
551         if (!strcmp(argv[i], "-z")
552             || !strcmp(argv[i], "--without-gui")
553             || !strcmp(argv[i], "-p")
554             || !strncmp(argv[i], "--print", 7)
555             || !strcmp(argv[i], "-e")
556             || !strncmp(argv[i], "--export-png", 12)
557             || !strcmp(argv[i], "-l")
558             || !strncmp(argv[i], "--export-plain-svg", 12)
559             || !strcmp(argv[i], "-i")
560             || !strncmp(argv[i], "--export-area-drawing", 21)
561             || !strcmp(argv[i], "-D")
562             || !strncmp(argv[i], "--export-area-canvas", 20)
563             || !strcmp(argv[i], "-C")
564             || !strncmp(argv[i], "--export-id", 12)
565             || !strcmp(argv[i], "-P")
566             || !strncmp(argv[i], "--export-ps", 11)
567             || !strcmp(argv[i], "-E")
568             || !strncmp(argv[i], "--export-eps", 12)
569             || !strcmp(argv[i], "-A")
570             || !strncmp(argv[i], "--export-pdf", 12)
571 #ifdef WIN32
572             || !strcmp(argv[i], "-M")
573             || !strncmp(argv[i], "--export-emf", 12)
574 #endif //WIN32
575             || !strcmp(argv[i], "-W")
576             || !strncmp(argv[i], "--query-width", 13)
577             || !strcmp(argv[i], "-H")
578             || !strncmp(argv[i], "--query-height", 14)
579             || !strcmp(argv[i], "-S")
580             || !strncmp(argv[i], "--query-all", 11)
581             || !strcmp(argv[i], "-X")
582             || !strncmp(argv[i], "--query-x", 13)
583             || !strcmp(argv[i], "-Y")
584             || !strncmp(argv[i], "--query-y", 14)
585             || !strcmp(argv[i], "--vacuum-defs")
586            )
587         {
588             /* main_console handles any exports -- not the gui */
589             use_gui = FALSE;
590             break;
591         } else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "--with-gui")) {
592             use_gui = TRUE;
593             break;
594         }
595     }
597 #ifdef WIN32
598 #ifndef REPLACEARGS_ANSI
599     if ( PrintWin32::is_os_wide() )
600 #endif // REPLACEARGS_ANSI
601     {
602         // If the call fails, we'll need to convert charsets
603         needToRecodeParams = !replaceArgs( argc, argv );
604     }
605 #endif // WIN32
607     /// \todo  Should this be a static object (see inkscape.cpp)?
608     Inkscape::NSApplication::Application app(argc, argv, use_gui, sp_new_gui);
610     return app.run();
616 void fixupSingleFilename( gchar **orig, gchar **spare )
618     if ( orig && *orig && **orig ) {
619         GError *error = NULL;
620         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(*orig, -1, NULL, NULL, &error);
621         if ( newFileName )
622         {
623             *orig = newFileName;
624             if ( spare ) {
625                 *spare = newFileName;
626             }
627 //             g_message("Set a replacement fixup");
628         }
629     }
634 GSList *fixupFilenameEncoding( GSList* fl )
636     GSList *newFl = NULL;
637     while ( fl ) {
638         gchar *fn = static_cast<gchar*>(fl->data);
639         fl = g_slist_remove( fl, fl->data );
640         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(fn, -1, NULL, NULL, NULL);
641         if ( newFileName ) {
643             if ( 0 )
644             {
645                 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
646                 gchar *safeNewFn = Inkscape::IO::sanitizeString(newFileName);
647                 GtkWidget *w = gtk_message_dialog_new( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
648                                                        "Note: Converted '%s' to '%s'", safeFn, safeNewFn );
649                 gtk_dialog_run (GTK_DIALOG (w));
650                 gtk_widget_destroy (w);
651                 g_free(safeNewFn);
652                 g_free(safeFn);
653             }
655             g_free( fn );
656             fn = newFileName;
657             newFileName = 0;
658         }
659         else
660             if ( 0 )
661         {
662             gchar *safeFn = Inkscape::IO::sanitizeString(fn);
663             GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "Error: Unable to convert '%s'", safeFn );
664             gtk_dialog_run (GTK_DIALOG (w));
665             gtk_widget_destroy (w);
666             g_free(safeFn);
667         }
668         newFl = g_slist_append( newFl, fn );
669     }
670     return newFl;
673 int sp_common_main( int argc, char const **argv, GSList **flDest )
675     /// \todo fixme: Move these to some centralized location (Lauris)
676     sp_object_type_register("sodipodi:namedview", SP_TYPE_NAMEDVIEW);
677     sp_object_type_register("sodipodi:guide", SP_TYPE_GUIDE);
680     // temporarily switch gettext encoding to locale, so that help messages can be output properly
681     gchar const *charset;
682     g_get_charset(&charset);
684     bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
686     poptContext ctx = poptGetContext(NULL, argc, argv, options, 0);
687     poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
688     g_return_val_if_fail(ctx != NULL, 1);
690     /* Collect own arguments */
691     GSList *fl = sp_process_args(ctx);
692     poptFreeContext(ctx);
694     // now switch gettext back to UTF-8 (for GUI)
695     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
697     // Now let's see if the file list still holds up
698     if ( needToRecodeParams )
699     {
700         fl = fixupFilenameEncoding( fl );
701     }
703     // Check the globals for filename-fixup
704     if ( needToRecodeParams )
705     {
706         fixupSingleFilename( &sp_export_png, &sp_export_png_utf8 );
707         fixupSingleFilename( &sp_export_svg, &sp_export_svg_utf8 );
708         fixupSingleFilename( &sp_global_printer, &sp_global_printer_utf8 );
709     }
710     else
711     {
712         if ( sp_export_png )
713             sp_export_png_utf8 = g_strdup( sp_export_png );
714         if ( sp_export_svg )
715             sp_export_svg_utf8 = g_strdup( sp_export_svg );
716         if ( sp_global_printer )
717             sp_global_printer_utf8 = g_strdup( sp_global_printer );
718     }
720     // Return the list if wanted, else free it up.
721     if ( flDest ) {
722         *flDest = fl;
723         fl = 0;
724     } else {
725         while ( fl ) {
726             g_free( fl->data );
727             fl = g_slist_remove( fl, fl->data );
728         }
729     }
730     return 0;
733 static void
734 snooper(GdkEvent *event, gpointer /*data*/) {
735     if(inkscape_mapalt())  /* returns the map of the keyboard modifier to map to Alt, zero if no mapping */
736     {
737         GdkModifierType mapping=(GdkModifierType)inkscape_mapalt();
738         switch (event->type) {
739             case GDK_MOTION_NOTIFY:
740                 if(event->motion.state & mapping) {
741                     event->motion.state|=GDK_MOD1_MASK;
742                 }
743                 break;
744             case GDK_BUTTON_PRESS:
745                 if(event->button.state & mapping) {
746                     event->button.state|=GDK_MOD1_MASK;
747                 }
748                 break;
749              case GDK_KEY_PRESS:
750                  if(event->key.state & mapping) {
751                      event->key.state|=GDK_MOD1_MASK;
752                  }
753                  break;
754         default:
755             break;
756         }
757     }
758     gtk_main_do_event (event);
761 int
762 sp_main_gui(int argc, char const **argv)
764     Gtk::Main main_instance (&argc, const_cast<char ***>(&argv));
766     GSList *fl = NULL;
767     int retVal = sp_common_main( argc, argv, &fl );
768     g_return_val_if_fail(retVal == 0, 1);
770     inkscape_gtk_stock_init();
772     gdk_event_handler_set((GdkEventFunc)snooper, NULL, NULL);
774     Inkscape::Debug::log_display_config();
776     /* Set default icon */
777     gchar *filename = (gchar *) g_build_filename (INKSCAPE_APPICONDIR, "inkscape.png", NULL);
778     if (Inkscape::IO::file_test(filename, (GFileTest)(G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK))) {
779         gtk_window_set_default_icon_from_file(filename, NULL);
780     }
781     g_free (filename);
782     filename = 0;
784     gboolean create_new = TRUE;
786     /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
787     inkscape_application_init(argv[0], true);
789     while (fl) {
790         if (sp_file_open((gchar *)fl->data,NULL)) {
791             create_new=FALSE;
792         }
793         fl = g_slist_remove(fl, fl->data);
794     }
795     if (create_new) {
796         sp_file_new_default();
797     }
799     Glib::signal_idle().connect(sigc::ptr_fun(&Inkscape::CmdLineAction::idle));
800     main_instance.run();
802 #ifdef WIN32
803     //We might not need anything here
804     //sp_win32_finish(); <-- this is a NOP func
805 #endif
807     return 0;
810 int
811 sp_main_console(int argc, char const **argv)
813     /* We are started in text mode */
815     /* Do this g_type_init(), so that we can use Xft/Freetype2 (Pango)
816      * in a non-Gtk environment.  Used in libnrtype's
817      * FontInstance.cpp and FontFactory.cpp.
818      * http://mail.gnome.org/archives/gtk-list/2003-December/msg00063.html
819      */
820     g_type_init();
821     char **argv2 = const_cast<char **>(argv);
822     gtk_init_check( &argc, &argv2 );
823     //setlocale(LC_ALL, "");
825     GSList *fl = NULL;
826     int retVal = sp_common_main( argc, argv, &fl );
827     g_return_val_if_fail(retVal == 0, 1);
829     if (fl == NULL) {
830         g_print("Nothing to do!\n");
831         exit(0);
832     }
834     inkscape_application_init(argv[0], false);
836     while (fl) {
837         SPDocument *doc;
839         doc = Inkscape::Extension::open(NULL, (gchar *)fl->data);
840         if (doc == NULL) {
841             doc = Inkscape::Extension::open(Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), (gchar *)fl->data);
842         }
843         if (doc == NULL) {
844             g_warning("Specified document %s cannot be opened (is it valid SVG file?)", (gchar *) fl->data);
845         } else {
846             if (sp_vacuum_defs) {
847                 vacuum_document(doc);
848             }
849             if (sp_vacuum_defs && !sp_export_svg) {
850                 // save under the name given in the command line
851                 sp_repr_save_file(doc->rdoc, (gchar *)fl->data, SP_SVG_NS_URI);
852             }
853             if (sp_global_printer) {
854                 sp_print_document_to_file(doc, sp_global_printer);
855             }
856             if (sp_export_png) {
857                 sp_do_export_png(doc);
858             }
859             if (sp_export_svg) {
860                 Inkscape::XML::Document *rdoc;
861                 Inkscape::XML::Node *repr;
862                 rdoc = sp_repr_document_new("svg:svg");
863                 repr = rdoc->root();
864                 repr = sp_document_root(doc)->updateRepr(rdoc, repr, SP_OBJECT_WRITE_BUILD);
865                 sp_repr_save_file(repr->document(), sp_export_svg, SP_SVG_NS_URI);
866             }
867             if (sp_export_ps) {
868                 do_export_ps(doc, sp_export_ps, "image/x-postscript");
869             }
870             if (sp_export_eps) {
871                 do_export_ps(doc, sp_export_eps, "image/x-e-postscript");
872             }
873             if (sp_export_pdf) {
874                 do_export_pdf(doc, sp_export_pdf, "application/pdf");
875             }
876 #ifdef WIN32
877             if (sp_export_emf) {
878                 do_export_emf(doc, sp_export_emf, "image/x-emf");
879             }
880 #endif //WIN32
881             if (sp_query_all) {
882                 do_query_all (doc);
883             } else if (sp_query_width || sp_query_height) {
884                 do_query_dimension (doc, true, sp_query_width? NR::X : NR::Y, sp_query_id);
885             } else if (sp_query_x || sp_query_y) {
886                 do_query_dimension (doc, false, sp_query_x? NR::X : NR::Y, sp_query_id);
887             }
888         }
890         fl = g_slist_remove(fl, fl->data);
891     }
893     inkscape_unref();
895     return 0;
898 static void
899 do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id)
901     SPObject *o = NULL;
903     if (id) {
904         o = doc->getObjectById(id);
905         if (o) {
906             if (!SP_IS_ITEM (o)) {
907                 g_warning("Object with id=\"%s\" is not a visible item. Cannot query dimensions.", id);
908                 return;
909             }
910         } else {
911             g_warning("Object with id=\"%s\" is not found. Cannot query dimensions.", id);
912             return;
913         }
914     } else {
915         o = SP_DOCUMENT_ROOT(doc);
916     }
918     if (o) {
919         sp_document_ensure_up_to_date (doc);
920         SPItem *item = ((SPItem *) o);
922         // "true" SVG bbox for scripting
923         boost::optional<NR::Rect> area = item->getBounds(sp_item_i2doc_affine(item));
924         if (area) {
925             Inkscape::SVGOStringStream os;
926             if (extent) {
927                 os << area->extent(axis);
928             } else {
929                 os << area->min()[axis];
930             }
931             g_print ("%s", os.str().c_str());
932         } else {
933             g_print("0");
934         }
935     }
938 static void
939 do_query_all (SPDocument *doc)
941     SPObject *o = NULL;
943     o = SP_DOCUMENT_ROOT(doc);
945     if (o) {
946         sp_document_ensure_up_to_date (doc);
947         do_query_all_recurse(o);
948     }
951 static void
952 do_query_all_recurse (SPObject *o)
954     SPItem *item = ((SPItem *) o);
955     if (o->id && SP_IS_ITEM(item)) {
956         boost::optional<NR::Rect> area = item->getBounds(sp_item_i2doc_affine(item));
957         if (area) {
958             Inkscape::SVGOStringStream os;
959             os << o->id;
960             os << "," << area->min()[NR::X];
961             os << "," << area->min()[NR::Y];
962             os << "," << area->extent(NR::X);
963             os << "," << area->extent(NR::Y);
964             g_print ("%s\n", os.str().c_str());
965         }
966     }
968     SPObject *child = o->children;
969     while (child) {
970         do_query_all_recurse (child);
971         child = child->next;
972     }
976 static void
977 sp_do_export_png(SPDocument *doc)
979     const gchar *filename = NULL;
980     gdouble dpi = 0.0;
982     if (sp_export_use_hints && (!sp_export_id && !sp_export_area_drawing)) {
983         g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored.");
984     }
986     GSList *items = NULL;
988     NRRect area;
989     if (sp_export_id || sp_export_area_drawing) {
991         SPObject *o = NULL;
992         SPObject *o_area = NULL;
993         if (sp_export_id && sp_export_area_drawing) {
994             o = doc->getObjectById(sp_export_id);
995             o_area = SP_DOCUMENT_ROOT (doc);
996         } else if (sp_export_id) {
997             o = doc->getObjectById(sp_export_id);
998             o_area = o;
999         } else if (sp_export_area_drawing) {
1000             o = SP_DOCUMENT_ROOT (doc);
1001             o_area = o;
1002         }
1004         if (o) {
1005             if (!SP_IS_ITEM (o)) {
1006                 g_warning("Object with id=\"%s\" is not a visible item. Nothing exported.", sp_export_id);
1007                 return;
1008             }
1010             items = g_slist_prepend (items, SP_ITEM(o));
1012             if (sp_export_id_only) {
1013                 g_print("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id);
1014             }
1016             if (sp_export_use_hints) {
1018                 // retrieve export filename hint
1019                 const gchar *fn_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-filename");
1020                 if (fn_hint) {
1021                     if (sp_export_png) {
1022                         g_warning ("Using export filename from the command line (--export-png). Filename hint %s is ignored.", fn_hint);
1023                         filename = sp_export_png;
1024                     } else {
1025                         filename = fn_hint;
1026                     }
1027                 } else {
1028                     g_warning ("Export filename hint not found for the object.");
1029                     filename = sp_export_png;
1030                 }
1032                 // retrieve export dpi hints
1033                 const gchar *dpi_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
1034                 if (dpi_hint) {
1035                     if (sp_export_dpi || sp_export_width || sp_export_height) {
1036                         g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint);
1037                     } else {
1038                         dpi = atof(dpi_hint);
1039                     }
1040                 } else {
1041                     g_warning ("Export DPI hint not found for the object.");
1042                 }
1044             }
1046             // write object bbox to area
1047             sp_document_ensure_up_to_date (doc);
1048             sp_item_invoke_bbox((SPItem *) o_area, &area, sp_item_i2r_affine((SPItem *) o_area), TRUE);
1049         } else {
1050             g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
1051             return;
1052         }
1053     }
1055     if (sp_export_area) {
1056         /* Try to parse area (given in SVG pixels) */
1057         if (!sscanf(sp_export_area, "%lg:%lg:%lg:%lg", &area.x0, &area.y0, &area.x1, &area.y1) == 4) {
1058             g_warning("Cannot parse export area '%s'; use 'x0:y0:x1:y1'. Nothing exported.", sp_export_area);
1059             return;
1060         }
1061         if ((area.x0 >= area.x1) || (area.y0 >= area.y1)) {
1062             g_warning("Export area '%s' has negative width or height. Nothing exported.", sp_export_area);
1063             return;
1064         }
1065     } else if (sp_export_area_canvas || !(sp_export_id || sp_export_area_drawing)) {
1066         /* Export the whole canvas */
1067         sp_document_ensure_up_to_date (doc);
1068         area.x0 = SP_ROOT(doc->root)->x.computed;
1069         area.y0 = SP_ROOT(doc->root)->y.computed;
1070         area.x1 = area.x0 + sp_document_width (doc);
1071         area.y1 = area.y0 + sp_document_height (doc);
1072     }
1074     // set filename and dpi from options, if not yet set from the hints
1075     if (!filename) {
1076         if (!sp_export_png) {
1077             g_warning ("No export filename given and no filename hint. Nothing exported.");
1078             return;
1079         }
1080         filename = sp_export_png;
1081     }
1083     if (sp_export_dpi && dpi == 0.0) {
1084         dpi = atof(sp_export_dpi);
1085         if ((dpi < 0.1) || (dpi > 10000.0)) {
1086             g_warning("DPI value %s out of range [0.1 - 10000.0]. Nothing exported.", sp_export_dpi);
1087             return;
1088         }
1089         g_print("DPI: %g\n", dpi);
1090     }
1092     if (sp_export_area_snap) {
1093         area.x0 = std::floor (area.x0);
1094         area.y0 = std::floor (area.y0);
1095         area.x1 = std::ceil (area.x1);
1096         area.y1 = std::ceil (area.y1);
1097     }
1099     // default dpi
1100     if (dpi == 0.0)
1101         dpi = PX_PER_IN;
1103     unsigned long int width = 0;
1104     unsigned long int height = 0;
1106     if (sp_export_width) {
1107         errno=0;
1108         width = strtoul(sp_export_width, NULL, 0);
1109         if ((width < 1) || (width > PNG_UINT_31_MAX) || (errno == ERANGE) ) {
1110             g_warning("Export width %lu out of range (1 - %lu). Nothing exported.", width, (unsigned long int)PNG_UINT_31_MAX);
1111             return;
1112         }
1113         dpi = (gdouble) width * PX_PER_IN / (area.x1 - area.x0);
1114     }
1116     if (sp_export_height) {
1117         errno=0;
1118         height = strtoul(sp_export_height, NULL, 0);
1119         if ((height < 1) || (height > PNG_UINT_31_MAX)) {
1120             g_warning("Export height %lu out of range (1 - %lu). Nothing exported.", height, (unsigned long int)PNG_UINT_31_MAX);
1121             return;
1122         }
1123         dpi = (gdouble) height * PX_PER_IN / (area.y1 - area.y0);
1124     }
1126     if (!sp_export_width) {
1127         width = (unsigned long int) ((area.x1 - area.x0) * dpi / PX_PER_IN + 0.5);
1128     }
1130     if (!sp_export_height) {
1131         height = (unsigned long int) ((area.y1 - area.y0) * dpi / PX_PER_IN + 0.5);
1132     }
1134     guint32 bgcolor = 0x00000000;
1135     if (sp_export_background) {
1136         // override the page color
1137         bgcolor = sp_svg_read_color(sp_export_background, 0xffffff00);
1138         bgcolor |= 0xff; // default is no opacity
1139     } else {
1140         // read from namedview
1141         Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
1142         if (nv && nv->attribute("pagecolor"))
1143             bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
1144         if (nv && nv->attribute("inkscape:pageopacity"))
1145             bgcolor |= SP_COLOR_F_TO_U(sp_repr_get_double_attribute (nv, "inkscape:pageopacity", 1.0));
1146     }
1148     if (sp_export_background_opacity) {
1149         // override opacity
1150         gfloat value;
1151         if (sp_svg_number_read_f (sp_export_background_opacity, &value)) {
1152             if (value > 1.0) {
1153                 value = CLAMP (value, 1.0f, 255.0f);
1154                 bgcolor &= (guint32) 0xffffff00;
1155                 bgcolor |= (guint32) floor(value);
1156             } else {
1157                 value = CLAMP (value, 0.0f, 1.0f);
1158                 bgcolor &= (guint32) 0xffffff00;
1159                 bgcolor |= SP_COLOR_F_TO_U(value);
1160             }
1161         }
1162     }
1164     g_print("Background RRGGBBAA: %08x\n", bgcolor);
1166     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);
1168     g_print("Bitmap saved as: %s\n", filename);
1170     if ((width >= 1) && (height >= 1) && (width <= PNG_UINT_31_MAX) && (height <= PNG_UINT_31_MAX)) {
1171         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);
1172     } else {
1173         g_warning("Calculated bitmap dimensions %lu %lu are out of range (1 - %lu). Nothing exported.", width, height, (unsigned long int)PNG_UINT_31_MAX);
1174     }
1176     g_slist_free (items);
1180 /**
1181  *  Perform an export of either PS or EPS.
1182  *
1183  *  \param doc Document to export.
1184  *  \param uri URI to export to.
1185  *  \param mime MIME type to export as.
1186  */
1188 static void do_export_ps(SPDocument* doc, gchar const* uri, char const* mime)
1190     Inkscape::Extension::DB::OutputList o;
1191     Inkscape::Extension::db.get_output_list(o);
1192     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1193     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1194         i++;
1195     }
1197     if (i == o.end())
1198     {
1199         g_warning ("Could not find an extension to export to MIME type %s.", mime);
1200         return;
1201     }
1203     bool old_text_to_path = false;
1204     bool old_font_embedded = false;
1205     bool old_bbox_page = false;
1207     try {
1208         old_text_to_path = (*i)->get_param_bool("textToPath");
1209         (*i)->set_param_bool("textToPath", sp_export_text_to_path);
1210     }
1211     catch (...) {
1212         g_warning ("Could not set export-text-to-path option for this export.");
1213     }
1215     try {
1216         old_font_embedded = (*i)->get_param_bool("fontEmbedded");
1217         (*i)->set_param_bool("fontEmbedded", sp_export_font);
1218     }
1219     catch (...) {
1220         g_warning ("Could not set export-font option for this export.");
1221     }
1223     try {
1224         old_bbox_page = (*i)->get_param_bool("pageBoundingBox");
1225         (*i)->set_param_bool("pageBoundingBox", sp_export_bbox_page);
1226     }
1227     catch (...) {
1228         g_warning ("Could not set export-bbox-page option for this export.");
1229     }
1231     (*i)->save(doc, uri);
1233     try {
1234         (*i)->set_param_bool("textToPath", old_text_to_path);
1235         (*i)->set_param_bool("fontEmbedded", old_font_embedded);
1236         (*i)->set_param_bool("pageBoundingBox", old_bbox_page);
1237     }
1238     catch (...) {
1240     }
1243 /**
1244  *  Perform a PDF export
1245  *
1246  *  \param doc Document to export.
1247  *  \param uri URI to export to.
1248  *  \param mime MIME type to export as.
1249  */
1251 static void do_export_pdf(SPDocument* doc, gchar const* uri, char const* mime)
1253     Inkscape::Extension::DB::OutputList o;
1254     Inkscape::Extension::db.get_output_list(o);
1255     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1256     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1257         i++;
1258     }
1260     if (i == o.end())
1261     {
1262         g_warning ("Could not find an extension to export to MIME type %s.", mime);
1263         return;
1264     }
1266     if (sp_export_id) {
1267         SPObject *o = doc->getObjectById(sp_export_id);
1268         if (o == NULL) {
1269             g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
1270             return;
1271         }
1272         (*i)->set_param_string ("exportId", sp_export_id);
1273     } else {
1274         (*i)->set_param_string ("exportId", "");
1275     }
1277     if (sp_export_area_drawing) {
1278         (*i)->set_param_bool ("exportDrawing", TRUE);
1279     } else {
1280         (*i)->set_param_bool ("exportDrawing", FALSE);
1281     }
1283     if (sp_export_area_canvas) {
1284         (*i)->set_param_bool ("exportCanvas", TRUE);
1285     } else {
1286         (*i)->set_param_bool ("exportCanvas", FALSE);
1287     }
1289     if (sp_export_text_to_path) {
1290         (*i)->set_param_bool("textToPath", TRUE);
1291     } else {
1292         (*i)->set_param_bool("textToPath", FALSE);
1293     }
1295     (*i)->save(doc, uri);
1298 #ifdef WIN32
1299 /**
1300  *  Export a document to EMF
1301  *
1302  *  \param doc Document to export.
1303  *  \param uri URI to export to.
1304  *  \param mime MIME type to export as (should be "image/x-emf")
1305  */
1307 static void do_export_emf(SPDocument* doc, gchar const* uri, char const* mime)
1309     Inkscape::Extension::DB::OutputList o;
1310     Inkscape::Extension::db.get_output_list(o);
1311     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1312     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1313         i++;
1314     }
1316     if (i == o.end())
1317     {
1318         g_warning ("Could not find an extension to export to MIME type %s.", mime);
1319         return;
1320     }
1322     (*i)->save(doc, uri);
1324 #endif //WIN32
1326 #ifdef WIN32
1327 bool replaceArgs( int& argc, char**& argv )
1329     bool worked = false;
1331 #ifdef REPLACEARGS_DEBUG
1332     MessageBoxA( NULL, "GetCommandLineW() getting called", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1333 #endif // REPLACEARGS_DEBUG
1335     wchar_t* line = GetCommandLineW();
1336     if ( line )
1337     {
1338 #ifdef REPLACEARGS_DEBUG
1339         {
1340             gchar* utf8Line = g_utf16_to_utf8( (gunichar2*)line, -1, NULL, NULL, NULL );
1341             if ( utf8Line )
1342             {
1343                 gchar *safe = Inkscape::IO::sanitizeString(utf8Line);
1344                 {
1345                     char tmp[strlen(safe) + 32];
1346                     snprintf( tmp, sizeof(tmp), "GetCommandLineW() = '%s'", safe );
1347                     MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1348                 }
1349             }
1350         }
1351 #endif // REPLACEARGS_DEBUG
1353         int numArgs = 0;
1354         wchar_t** parsed = CommandLineToArgvW( line, &numArgs );
1356 #ifdef REPLACEARGS_ANSI
1357 // test code for trying things on Win95/98/ME
1358         if ( !parsed )
1359         {
1360 #ifdef REPLACEARGS_DEBUG
1361             MessageBoxA( NULL, "Unable to process command-line. Faking it", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1362 #endif // REPLACEARGS_DEBUG
1363             int lineLen = wcslen(line) + 1;
1364             wchar_t* lineDup = new wchar_t[lineLen];
1365             wcsncpy( lineDup, line, lineLen );
1367             int pos = 0;
1368             bool inQuotes = false;
1369             bool inWhitespace = true;
1370             std::vector<int> places;
1371             while ( lineDup[pos] )
1372             {
1373                 if ( inQuotes )
1374                 {
1375                     if ( lineDup[pos] == L'"' )
1376                     {
1377                         inQuotes = false;
1378                     }
1379                 }
1380                 else if ( lineDup[pos] == L'"' )
1381                 {
1382                     inQuotes = true;
1383                     inWhitespace = false;
1384                     places.push_back(pos);
1385                 }
1386                 else if ( lineDup[pos] == L' ' || lineDup[pos] == L'\t' )
1387                 {
1388                     if ( !inWhitespace )
1389                     {
1390                         inWhitespace = true;
1391                         lineDup[pos] = 0;
1392                     }
1393                 }
1394                 else if ( inWhitespace && (lineDup[pos] != L' ' && lineDup[pos] != L'\t') )
1395                 {
1396                     inWhitespace = false;
1397                     places.push_back(pos);
1398                 }
1399                 else
1400                 {
1401                     // consume
1402                 }
1403                 pos++;
1404             }
1405 #ifdef REPLACEARGS_DEBUG
1406             {
1407                 char tmp[256];
1408                 snprintf( tmp, sizeof(tmp), "Counted %d args", places.size() );
1409                 MessageBoxA( NULL, tmp, "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1410             }
1411 #endif // REPLACEARGS_DEBUG
1413             wchar_t** block = new wchar_t*[places.size()];
1414             int i = 0;
1415             for ( std::vector<int>::iterator it = places.begin(); it != places.end(); it++ )
1416             {
1417                 block[i++] = &lineDup[*it];
1418             }
1419             parsed = block;
1420             numArgs = places.size();
1421         }
1422 #endif // REPLACEARGS_ANSI
1424         if ( parsed )
1425         {
1426             std::vector<wchar_t*>expandedArgs;
1427             if ( numArgs > 0 )
1428             {
1429                 expandedArgs.push_back( parsed[0] );
1430             }
1432             for ( int i1 = 1; i1 < numArgs; i1++ )
1433             {
1434                 bool wildcarded = (wcschr(parsed[i1], L'?') != NULL) || (wcschr(parsed[i1], L'*') != NULL);
1435                 wildcarded &= parsed[i1][0] != L'"';
1436                 wildcarded &= parsed[i1][0] != L'-';
1437                 if ( wildcarded )
1438                 {
1439 #ifdef REPLACEARGS_ANSI
1440                     WIN32_FIND_DATAA data;
1441 #else
1442                     WIN32_FIND_DATAW data;
1443 #endif // REPLACEARGS_ANSI
1445                     memset((void *)&data, 0, sizeof(data));
1447                     int baseLen = wcslen(parsed[i1]) + 2;
1448                     wchar_t* base = new wchar_t[baseLen];
1449                     wcsncpy( base, parsed[i1], baseLen );
1450                     wchar_t* last = wcsrchr( base, L'\\' );
1451                     if ( last )
1452                     {
1453                         last[1] = 0;
1454                     }
1455                     else
1456                     {
1457                         base[0] = 0;
1458                     }
1459                     baseLen = wcslen( base );
1461 #ifdef REPLACEARGS_ANSI
1462                     char target[MAX_PATH];
1463                     if ( WideCharToMultiByte( CP_ACP, 0, parsed[i1], -1, target, sizeof(target), NULL, NULL) )
1464                     {
1465                         HANDLE hf = FindFirstFileA( target, &data );
1466 #else
1467                         HANDLE hf = FindFirstFileW( parsed[i1], &data );
1468 #endif // REPLACEARGS_ANSI
1469                         if ( hf != INVALID_HANDLE_VALUE )
1470                         {
1471                             BOOL found = TRUE;
1472                             do
1473                             {
1474 #ifdef REPLACEARGS_ANSI
1475                                 int howMany = MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, NULL, 0 );
1476                                 if ( howMany > 0 )
1477                                 {
1478                                     howMany += baseLen;
1479                                     wchar_t* tmp = new wchar_t[howMany + 1];
1480                                     wcsncpy( tmp, base, howMany + 1 );
1481                                     MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, tmp + baseLen, howMany + 1 - baseLen );
1482                                     expandedArgs.push_back( tmp );
1483                                     found = FindNextFileA( hf, &data );
1484                                 }
1485 #else
1486                                 int howMany = wcslen(data.cFileName) + baseLen;
1487                                 wchar_t* tmp = new wchar_t[howMany + 1];
1488                                 wcsncpy( tmp, base, howMany + 1 );
1489                                 wcsncat( tmp, data.cFileName, howMany + 1 );
1490                                 expandedArgs.push_back( tmp );
1491                                 found = FindNextFileW( hf, &data );
1492 #endif // REPLACEARGS_ANSI
1493                             } while ( found );
1495                             FindClose( hf );
1496                         }
1497                         else
1498                         {
1499                             expandedArgs.push_back( parsed[i1] );
1500                         }
1501 #ifdef REPLACEARGS_ANSI
1502                     }
1503 #endif // REPLACEARGS_ANSI
1505                     delete[] base;
1506                 }
1507                 else
1508                 {
1509                     expandedArgs.push_back( parsed[i1] );
1510                 }
1511             }
1513             {
1514                 wchar_t** block = new wchar_t*[expandedArgs.size()];
1515                 int iz = 0;
1516                 for ( std::vector<wchar_t*>::iterator it = expandedArgs.begin(); it != expandedArgs.end(); it++ )
1517                 {
1518                     block[iz++] = *it;
1519                 }
1520                 parsed = block;
1521                 numArgs = expandedArgs.size();
1522             }
1524             std::vector<gchar*> newArgs;
1525             for ( int i = 0; i < numArgs; i++ )
1526             {
1527                 gchar* replacement = g_utf16_to_utf8( (gunichar2*)parsed[i], -1, NULL, NULL, NULL );
1528                 if ( replacement )
1529                 {
1530 #ifdef REPLACEARGS_DEBUG
1531                     gchar *safe2 = Inkscape::IO::sanitizeString(replacement);
1533                     if ( safe2 )
1534                     {
1535                         {
1536                             char tmp[1024];
1537                             snprintf( tmp, sizeof(tmp), "    [%2d] = '%s'", i, safe2 );
1538                             MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1539                         }
1540                         g_free( safe2 );
1541                     }
1542 #endif // REPLACEARGS_DEBUG
1544                     newArgs.push_back( replacement );
1545                 }
1546                 else
1547                 {
1548                     newArgs.push_back( blankParam );
1549                 }
1550             }
1552             // Now push our munged params to be the new argv and argc
1553             {
1554                 char** block = new char*[newArgs.size()];
1555                 int iz = 0;
1556                 for ( std::vector<char*>::iterator it = newArgs.begin(); it != newArgs.end(); it++ )
1557                 {
1558                     block[iz++] = *it;
1559                 }
1560                 argv = block;
1561                 argc = newArgs.size();
1562                 worked = true;
1563             }
1564         }
1565 #ifdef REPLACEARGS_DEBUG
1566         else
1567         {
1568             MessageBoxA( NULL, "Unable to process command-line", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1569         }
1570 #endif // REPLACEARGS_DEBUG
1571     }
1572 #ifdef REPLACEARGS_DEBUG
1573     else
1574     {
1575         {
1576             MessageBoxA( NULL,  "Unable to fetch result from GetCommandLineW()", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1577         }
1579         char* line2 = GetCommandLineA();
1580         if ( line2 )
1581         {
1582             gchar *safe = Inkscape::IO::sanitizeString(line2);
1583             {
1584                 {
1585                     char tmp[strlen(safe) + 32];
1586                     snprintf( tmp, sizeof(tmp), "GetCommandLineA() = '%s'", safe );
1587                     MessageBoxA( NULL, tmp, "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1588                 }
1589             }
1590         }
1591         else
1592         {
1593             MessageBoxA( NULL, "Unable to fetch result from GetCommandLineA()", "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1594         }
1595     }
1596 #endif // REPLACEARGS_DEBUG
1598     return worked;
1600 #endif // WIN32
1602 static GSList *
1603 sp_process_args(poptContext ctx)
1605     GSList *fl = NULL;
1607     gint a;
1608     while ((a = poptGetNextOpt(ctx)) >= 0) {
1609         switch (a) {
1610             case SP_ARG_FILE: {
1611                 gchar const *fn = poptGetOptArg(ctx);
1612                 if (fn != NULL) {
1613                     fl = g_slist_append(fl, g_strdup(fn));
1614                 }
1615                 break;
1616             }
1617             case SP_ARG_VERSION: {
1618                 printf("Inkscape %s (%s)\n", INKSCAPE_VERSION, __DATE__);
1619                 exit(0);
1620                 break;
1621             }
1622             case SP_ARG_EXTENSIONDIR: {
1623                 printf("%s\n", INKSCAPE_EXTENSIONDIR);
1624                 exit(0);
1625                 break;
1626             }
1627             case SP_ARG_VERB_LIST: {
1628                 // This really shouldn't go here, we should init the app.
1629                 // But, since we're just exiting in this path, there is
1630                 // no harm, and this is really a better place to put
1631                 // everything else.
1632                 Inkscape::Extension::init();
1633                 Inkscape::Verb::list();
1634                 exit(0);
1635                 break;
1636             }
1637             case SP_ARG_VERB:
1638             case SP_ARG_SELECT: {
1639                 gchar const *arg = poptGetOptArg(ctx);
1640                 if (arg != NULL) {
1641                     // printf("Adding in: %s\n", arg);
1642                     new Inkscape::CmdLineAction((a == SP_ARG_VERB), arg);
1643                 }
1644                 break;
1645             }
1646             default: {
1647                 break;
1648             }
1649         }
1650     }
1652     gchar const ** const args = poptGetArgs(ctx);
1653     if (args != NULL) {
1654         for (unsigned i = 0; args[i] != NULL; i++) {
1655             fl = g_slist_append(fl, g_strdup(args[i]));
1656         }
1657     }
1659     return fl;
1663 /*
1664   Local Variables:
1665   mode:c++
1666   c-file-style:"stroustrup"
1667   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1668   indent-tabs-mode:nil
1669   fill-column:99
1670   End:
1671 */
1672 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :