Code

add experimental modifier remapping
[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 <string.h>
37 #include <locale.h>
39 #include <popt.h>
40 #ifndef POPT_TABLEEND
41 #define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL }
42 #endif /* Not def: POPT_TABLEEND */
44 #include <libxml/tree.h>
45 #include <glib-object.h>
46 #include <gtk/gtkmain.h>
47 #include <gtk/gtksignal.h>
48 #include <gtk/gtkwindow.h>
49 #include <gtk/gtkbox.h>
51 #include "gc-core.h"
53 #include "macros.h"
54 #include "file.h"
55 #include "document.h"
56 #include "sp-object.h"
57 #include "interface.h"
58 #include "print.h"
59 #include "color.h"
60 #include "sp-item.h"
61 #include "sp-root.h"
62 #include "unit-constants.h"
64 #include "svg/svg.h"
65 #include "svg/svg-color.h"
66 #include "svg/stringstream.h"
68 #include "inkscape-private.h"
69 #include "inkscape-stock.h"
70 #include "inkscape_version.h"
72 #include "sp-namedview.h"
73 #include "sp-guide.h"
74 #include "sp-object-repr.h"
75 #include "xml/repr.h"
77 #include "io/sys.h"
79 #include "debug/logger.h"
80 #include "debug/log-display-config.h"
82 #include "helper/png-write.h"
84 #include <extension/extension.h>
85 #include <extension/system.h>
86 #include <extension/db.h>
87 #include <extension/output.h>
89 #ifdef WIN32
90 //#define REPLACEARGS_ANSI
91 //#define REPLACEARGS_DEBUG
93 #include "registrytool.h"
95 #include "extension/internal/win32.h"
96 using Inkscape::Extension::Internal::PrintWin32;
98 #endif // WIN32
100 #include "extension/init.h"
102 #include <glibmm/i18n.h>
103 #include <gtkmm/main.h>
105 #ifndef HAVE_BIND_TEXTDOMAIN_CODESET
106 #define bind_textdomain_codeset(p,c)
107 #endif
109 #include "application/application.h"
111 #include "main-cmdlineact.h"
113 enum {
114     SP_ARG_NONE,
115     SP_ARG_NOGUI,
116     SP_ARG_GUI,
117     SP_ARG_FILE,
118     SP_ARG_PRINT,
119     SP_ARG_EXPORT_PNG,
120     SP_ARG_EXPORT_DPI,
121     SP_ARG_EXPORT_AREA,
122     SP_ARG_EXPORT_AREA_DRAWING,
123     SP_ARG_EXPORT_AREA_CANVAS,
124     SP_ARG_EXPORT_AREA_SNAP,
125     SP_ARG_EXPORT_WIDTH,
126     SP_ARG_EXPORT_HEIGHT,
127     SP_ARG_EXPORT_ID,
128     SP_ARG_EXPORT_ID_ONLY,
129     SP_ARG_EXPORT_USE_HINTS,
130     SP_ARG_EXPORT_BACKGROUND,
131     SP_ARG_EXPORT_BACKGROUND_OPACITY,
132     SP_ARG_EXPORT_SVG,
133     SP_ARG_EXPORT_PS,
134     SP_ARG_EXPORT_EPS,
135     SP_ARG_EXPORT_PDF,
136     SP_ARG_EXPORT_TEXT_TO_PATH,
137     SP_ARG_EXPORT_FONT,
138     SP_ARG_EXPORT_BBOX_PAGE,
139     SP_ARG_EXTENSIONDIR,
140     SP_ARG_FIT_PAGE_TO_DRAWING,
141     SP_ARG_QUERY_X,
142     SP_ARG_QUERY_Y,
143     SP_ARG_QUERY_WIDTH,
144     SP_ARG_QUERY_HEIGHT,
145     SP_ARG_QUERY_ID,
146     SP_ARG_VERSION,
147     SP_ARG_VACUUM_DEFS,
148     SP_ARG_VERB_LIST,
149     SP_ARG_VERB,
150     SP_ARG_SELECT,
151     SP_ARG_LAST
152 };
154 int sp_main_gui(int argc, char const **argv);
155 int sp_main_console(int argc, char const **argv);
156 static void sp_do_export_png(SPDocument *doc);
157 static void do_export_ps(SPDocument* doc, gchar const* uri, char const *mime);
158 static void do_export_pdf(SPDocument* doc, gchar const* uri, char const *mime);
159 static void do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id);
162 static gchar *sp_global_printer = NULL;
163 static gchar *sp_export_png = NULL;
164 static gchar *sp_export_dpi = NULL;
165 static gchar *sp_export_area = NULL;
166 static gboolean sp_export_area_drawing = FALSE;
167 static gboolean sp_export_area_canvas = FALSE;
168 static gchar *sp_export_width = NULL;
169 static gchar *sp_export_height = NULL;
170 static gchar *sp_export_id = NULL;
171 static gchar *sp_export_background = NULL;
172 static gchar *sp_export_background_opacity = NULL;
173 static gboolean sp_export_area_snap = FALSE;
174 static gboolean sp_export_use_hints = FALSE;
175 static gboolean sp_export_id_only = FALSE;
176 static gchar *sp_export_svg = NULL;
177 static gchar *sp_export_ps = NULL;
178 static gchar *sp_export_eps = NULL;
179 static gchar *sp_export_pdf = NULL;
180 static gboolean sp_export_text_to_path = FALSE;
181 static gboolean sp_export_font = FALSE;
182 static gboolean sp_export_bbox_page = FALSE;
183 static gboolean sp_query_x = FALSE;
184 static gboolean sp_query_y = FALSE;
185 static gboolean sp_query_width = FALSE;
186 static gboolean sp_query_height = FALSE;
187 static gchar *sp_query_id = NULL;
188 static int sp_new_gui = FALSE;
189 static gboolean sp_vacuum_defs = FALSE;
191 static gchar *sp_export_png_utf8 = NULL;
192 static gchar *sp_export_svg_utf8 = NULL;
193 static gchar *sp_global_printer_utf8 = NULL;
195 #ifdef WIN32
196 static bool replaceArgs( int& argc, char**& argv );
197 #endif
198 static GSList *sp_process_args(poptContext ctx);
199 struct poptOption options[] = {
200     {"version", 'V',
201      POPT_ARG_NONE, NULL, SP_ARG_VERSION,
202      N_("Print the Inkscape version number"),
203      NULL},
205     {"without-gui", 'z',
206      POPT_ARG_NONE, NULL, SP_ARG_NOGUI,
207      N_("Do not use X server (only process files from console)"),
208      NULL},
210     {"with-gui", 'g',
211      POPT_ARG_NONE, NULL, SP_ARG_GUI,
212      N_("Try to use X server (even if $DISPLAY is not set)"),
213      NULL},
215     {"file", 'f',
216      POPT_ARG_STRING, NULL, SP_ARG_FILE,
217      N_("Open specified document(s) (option string may be excluded)"),
218      N_("FILENAME")},
220     {"print", 'p',
221      POPT_ARG_STRING, &sp_global_printer, SP_ARG_PRINT,
222      N_("Print document(s) to specified output file (use '| program' for pipe)"),
223      N_("FILENAME")},
225     {"export-png", 'e',
226      POPT_ARG_STRING, &sp_export_png, SP_ARG_EXPORT_PNG,
227      N_("Export document to a PNG file"),
228      N_("FILENAME")},
230     {"export-dpi", 'd',
231      POPT_ARG_STRING, &sp_export_dpi, SP_ARG_EXPORT_DPI,
232      N_("The resolution used for exporting SVG into bitmap (default 90)"),
233      N_("DPI")},
235     {"export-area", 'a',
236      POPT_ARG_STRING, &sp_export_area, SP_ARG_EXPORT_AREA,
237      N_("Exported area in SVG user units (default is the canvas; 0,0 is lower-left corner)"),
238      N_("x0:y0:x1:y1")},
240     {"export-area-drawing", 'D',
241      POPT_ARG_NONE, &sp_export_area_drawing, SP_ARG_EXPORT_AREA_DRAWING,
242      N_("Exported area is the entire drawing (not canvas)"),
243      NULL},
245     {"export-area-canvas", 'C',
246      POPT_ARG_NONE, &sp_export_area_canvas, SP_ARG_EXPORT_AREA_CANVAS,
247      N_("Exported area is the entire canvas"),
248      NULL},
250     {"export-area-snap", 0,
251      POPT_ARG_NONE, &sp_export_area_snap, SP_ARG_EXPORT_AREA_SNAP,
252      N_("Snap the bitmap export area outwards to the nearest integer values (in SVG user units)"),
253      NULL},
255     {"export-width", 'w',
256      POPT_ARG_STRING, &sp_export_width, SP_ARG_EXPORT_WIDTH,
257      N_("The width of exported bitmap in pixels (overrides export-dpi)"),
258      N_("WIDTH")},
260     {"export-height", 'h',
261      POPT_ARG_STRING, &sp_export_height, SP_ARG_EXPORT_HEIGHT,
262      N_("The height of exported bitmap in pixels (overrides export-dpi)"),
263      N_("HEIGHT")},
265     {"export-id", 'i',
266      POPT_ARG_STRING, &sp_export_id, SP_ARG_EXPORT_ID,
267      N_("The ID of the object to export"),
268      N_("ID")},
270     {"export-id-only", 'j',
271      POPT_ARG_NONE, &sp_export_id_only, SP_ARG_EXPORT_ID_ONLY,
272      // TRANSLATORS: this means: "Only export the object whose id is given in --export-id".
273      //  See "man inkscape" for details.
274      N_("Export just the object with export-id, hide all others (only with export-id)"),
275      NULL},
277     {"export-use-hints", 't',
278      POPT_ARG_NONE, &sp_export_use_hints, SP_ARG_EXPORT_USE_HINTS,
279      N_("Use stored filename and DPI hints when exporting (only with export-id)"),
280      NULL},
282     {"export-background", 'b',
283      POPT_ARG_STRING, &sp_export_background, SP_ARG_EXPORT_BACKGROUND,
284      N_("Background color of exported bitmap (any SVG-supported color string)"),
285      N_("COLOR")},
287     {"export-background-opacity", 'y',
288      POPT_ARG_STRING, &sp_export_background_opacity, SP_ARG_EXPORT_BACKGROUND_OPACITY,
289      N_("Background opacity of exported bitmap (either 0.0 to 1.0, or 1 to 255)"),
290      N_("VALUE")},
292     {"export-plain-svg", 'l',
293      POPT_ARG_STRING, &sp_export_svg, SP_ARG_EXPORT_SVG,
294      N_("Export document to plain SVG file (no sodipodi or inkscape namespaces)"),
295      N_("FILENAME")},
297     {"export-ps", 'P',
298      POPT_ARG_STRING, &sp_export_ps, SP_ARG_EXPORT_PS,
299      N_("Export document to a PS file"),
300      N_("FILENAME")},
302     {"export-eps", 'E',
303      POPT_ARG_STRING, &sp_export_eps, SP_ARG_EXPORT_EPS,
304      N_("Export document to an EPS file"),
305      N_("FILENAME")},
307     {"export-pdf", 'A',
308      POPT_ARG_STRING, &sp_export_pdf, SP_ARG_EXPORT_PDF,
309      N_("Export document to a PDF file"),
310      N_("FILENAME")},
312     {"export-text-to-path", 'T',
313      POPT_ARG_NONE, &sp_export_text_to_path, SP_ARG_EXPORT_TEXT_TO_PATH,
314      N_("Convert text object to paths on export (EPS)"),
315      NULL},
317     {"export-embed-fonts", 'F',
318      POPT_ARG_NONE, &sp_export_font, SP_ARG_EXPORT_FONT,
319      N_("Embed fonts on export (Type 1 only) (EPS)"),
320      NULL},
322     {"export-bbox-page", 'B',
323      POPT_ARG_NONE, &sp_export_bbox_page, SP_ARG_EXPORT_BBOX_PAGE,
324      N_("Export files with the bounding box set to the page size (EPS)"),
325      NULL},
327     {"query-x", 'X',
328      POPT_ARG_NONE, &sp_query_x, SP_ARG_QUERY_X,
329      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
330      N_("Query the X coordinate of the drawing or, if specified, of the object with --query-id"),
331      NULL},
333     {"query-y", 'Y',
334      POPT_ARG_NONE, &sp_query_y, SP_ARG_QUERY_Y,
335      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
336      N_("Query the Y coordinate of the drawing or, if specified, of the object with --query-id"),
337      NULL},
339     {"query-width", 'W',
340      POPT_ARG_NONE, &sp_query_width, SP_ARG_QUERY_WIDTH,
341      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
342      N_("Query the width of the drawing or, if specified, of the object with --query-id"),
343      NULL},
345     {"query-height", 'H',
346      POPT_ARG_NONE, &sp_query_height, SP_ARG_QUERY_HEIGHT,
347      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
348      N_("Query the height of the drawing or, if specified, of the object with --query-id"),
349      NULL},
351     {"query-id", 'I',
352      POPT_ARG_STRING, &sp_query_id, SP_ARG_QUERY_ID,
353      N_("The ID of the object whose dimensions are queried"),
354      N_("ID")},
356     {"extension-directory", 'x',
357      POPT_ARG_NONE, NULL, SP_ARG_EXTENSIONDIR,
358      // TRANSLATORS: this option makes Inkscape print the name (path) of the extension directory
359      N_("Print out the extension directory and exit"),
360      NULL},
362     {"vacuum-defs", 0,
363      POPT_ARG_NONE, &sp_vacuum_defs, SP_ARG_VACUUM_DEFS,
364      N_("Remove unused definitions from the defs section(s) of the document"),
365      NULL},
367     {"verb-list", 0,
368      POPT_ARG_NONE, NULL, SP_ARG_VERB_LIST,
369      N_("List the IDs of all the verbs in Inkscape"),
370      NULL},
372     {"verb", 0,
373      POPT_ARG_STRING, NULL, SP_ARG_VERB,
374      N_("Verb to call when Inkscape opens."),
375      N_("VERB-ID")},
377     {"select", 0,
378      POPT_ARG_STRING, NULL, SP_ARG_SELECT,
379      N_("Object ID to select when Inkscape opens."),
380      N_("OBJECT-ID")},
382     POPT_AUTOHELP POPT_TABLEEND
383 };
385 static bool needToRecodeParams = true;
386 gchar* blankParam = "";
388 int
389 main(int argc, char **argv)
391 #ifdef HAVE_FPSETMASK
392     /* This is inherited from Sodipodi code, where it was in #ifdef __FreeBSD__.  It's probably
393        safe to remove: the default mask is already 0 in C99, and in current FreeBSD according to
394        the fenv man page on www.freebsd.org, and in glibc according to (libc)FP Exceptions. */
395     fpsetmask(fpgetmask() & ~(FP_X_DZ | FP_X_INV));
396 #endif
398 #ifdef ENABLE_NLS
399 #ifdef WIN32
400     RegistryTool rt;
401     rt.setPathInfo();
402     gchar *pathBuf = g_strconcat(g_path_get_dirname(argv[0]), "\\", PACKAGE_LOCALE_DIR, NULL);
403     bindtextdomain(GETTEXT_PACKAGE, pathBuf);
404     g_free(pathBuf);
405 #else
406 #ifdef ENABLE_BINRELOC
407     bindtextdomain(GETTEXT_PACKAGE, BR_LOCALEDIR(""));
408 #else
409     bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
410 #endif
411 #endif
412     // Allow the user to override the locale directory by setting 
413     // the environment variable INKSCAPE_LOCALEDIR.
414     char *inkscape_localedir = getenv("INKSCAPE_LOCALEDIR");
415     if (inkscape_localedir != NULL) {
416         bindtextdomain(GETTEXT_PACKAGE, inkscape_localedir);
417     }
418 #endif
420     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
422 #ifdef ENABLE_NLS
423     textdomain(GETTEXT_PACKAGE);
424 #endif
426     LIBXML_TEST_VERSION
428     Inkscape::GC::init();
430     Inkscape::Debug::Logger::init();
432     gboolean use_gui;
433 #ifndef WIN32
434     use_gui = (getenv("DISPLAY") != NULL);
435 #else
436     /*
437       Set the current directory to the directory of the
438       executable.  This seems redundant, but is needed for
439       when inkscape.exe is executed from another directory.
440       We use relative paths on win32.
441       HKCR\svgfile\shell\open\command is a good example
442     */
443     /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
444     char *homedir = g_path_get_dirname(argv[0]);
445     SetCurrentDirectory(homedir);
446     g_free(homedir);
448     use_gui = TRUE;
449 #endif
450     /* Test whether with/without GUI is forced */
451     for (int i = 1; i < argc; i++) {
452         if (!strcmp(argv[i], "-z")
453             || !strcmp(argv[i], "--without-gui")
454             || !strcmp(argv[i], "-p")
455             || !strncmp(argv[i], "--print", 7)
456             || !strcmp(argv[i], "-e")
457             || !strncmp(argv[i], "--export-png", 12)
458             || !strcmp(argv[i], "-l")
459             || !strncmp(argv[i], "--export-plain-svg", 12)
460             || !strcmp(argv[i], "-i")
461             || !strncmp(argv[i], "--export-area-drawing", 21)
462             || !strcmp(argv[i], "-D")
463             || !strncmp(argv[i], "--export-area-canvas", 20)
464             || !strcmp(argv[i], "-C")
465             || !strncmp(argv[i], "--export-id", 12)
466             || !strcmp(argv[i], "-P")
467             || !strncmp(argv[i], "--export-ps", 11)
468             || !strcmp(argv[i], "-E")
469             || !strncmp(argv[i], "--export-eps", 12)
470             || !strcmp(argv[i], "-A")
471             || !strncmp(argv[i], "--export-pdf", 12)
472             || !strcmp(argv[i], "-W")
473             || !strncmp(argv[i], "--query-width", 13)
474             || !strcmp(argv[i], "-H")
475             || !strncmp(argv[i], "--query-height", 14)
476             || !strcmp(argv[i], "-X")
477             || !strncmp(argv[i], "--query-x", 13)
478             || !strcmp(argv[i], "-Y")
479             || !strncmp(argv[i], "--query-y", 14)
480             || !strcmp(argv[i], "--vacuum-defs")
481            )
482         {
483             /* main_console handles any exports -- not the gui */
484             use_gui = FALSE;
485             break;
486         } else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "--with-gui")) {
487             use_gui = TRUE;
488             break;
489         }
490     }
492 #ifdef WIN32
493 #ifndef REPLACEARGS_ANSI
494     if ( PrintWin32::is_os_wide() )
495 #endif // REPLACEARGS_ANSI
496     {
497         // If the call fails, we'll need to convert charsets
498         needToRecodeParams = !replaceArgs( argc, argv );
499     }
500 #endif // WIN32
502     /// \todo  Should this be a static object (see inkscape.cpp)?
503     Inkscape::NSApplication::Application app(argc, argv, use_gui, sp_new_gui);
505     return app.run();
508 void fixupSingleFilename( gchar **orig, gchar **spare )
510     if ( orig && *orig && **orig ) {
511         GError *error = NULL;
512         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(*orig, -1, NULL, NULL, &error);
513         if ( newFileName )
514         {
515             *orig = newFileName;
516             if ( spare ) {
517                 *spare = newFileName;
518             }
519 //             g_message("Set a replacement fixup");
520         }
521     }
524 GSList *fixupFilenameEncoding( GSList* fl )
526     GSList *newFl = NULL;
527     while ( fl ) {
528         gchar *fn = static_cast<gchar*>(fl->data);
529         fl = g_slist_remove( fl, fl->data );
530         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(fn, -1, NULL, NULL, NULL);
531         if ( newFileName ) {
533             if ( 0 )
534             {
535                 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
536                 gchar *safeNewFn = Inkscape::IO::sanitizeString(newFileName);
537                 GtkWidget *w = gtk_message_dialog_new( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
538                                                        "Note: Converted '%s' to '%s'", safeFn, safeNewFn );
539                 gtk_dialog_run (GTK_DIALOG (w));
540                 gtk_widget_destroy (w);
541                 g_free(safeNewFn);
542                 g_free(safeFn);
543             }
545             g_free( fn );
546             fn = newFileName;
547             newFileName = 0;
548         }
549         else
550             if ( 0 )
551         {
552             gchar *safeFn = Inkscape::IO::sanitizeString(fn);
553             GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "Error: Unable to convert '%s'", safeFn );
554             gtk_dialog_run (GTK_DIALOG (w));
555             gtk_widget_destroy (w);
556             g_free(safeFn);
557         }
558         newFl = g_slist_append( newFl, fn );
559     }
560     return newFl;
563 int sp_common_main( int argc, char const **argv, GSList **flDest )
565     /// \todo fixme: Move these to some centralized location (Lauris)
566     sp_object_type_register("sodipodi:namedview", SP_TYPE_NAMEDVIEW);
567     sp_object_type_register("sodipodi:guide", SP_TYPE_GUIDE);
570     // temporarily switch gettext encoding to locale, so that help messages can be output properly
571     gchar const *charset;
572     g_get_charset(&charset);
574     bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
576     poptContext ctx = poptGetContext(NULL, argc, argv, options, 0);
577     poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
578     g_return_val_if_fail(ctx != NULL, 1);
580     /* Collect own arguments */
581     GSList *fl = sp_process_args(ctx);
582     poptFreeContext(ctx);
584     // now switch gettext back to UTF-8 (for GUI)
585     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
587     // Now let's see if the file list still holds up
588     if ( needToRecodeParams )
589     {
590         fl = fixupFilenameEncoding( fl );
591     }
593     // Check the globals for filename-fixup
594     if ( needToRecodeParams )
595     {
596         fixupSingleFilename( &sp_export_png, &sp_export_png_utf8 );
597         fixupSingleFilename( &sp_export_svg, &sp_export_svg_utf8 );
598         fixupSingleFilename( &sp_global_printer, &sp_global_printer_utf8 );
599     }
600     else
601     {
602         if ( sp_export_png )
603             sp_export_png_utf8 = g_strdup( sp_export_png );
604         if ( sp_export_svg )
605             sp_export_svg_utf8 = g_strdup( sp_export_svg );
606         if ( sp_global_printer )
607             sp_global_printer_utf8 = g_strdup( sp_global_printer );
608     }
610     // Return the list if wanted, else free it up.
611     if ( flDest ) {
612         *flDest = fl;
613         fl = 0;
614     } else {
615         while ( fl ) {
616             g_free( fl->data );
617             fl = g_slist_remove( fl, fl->data );
618         }
619     }
620     return 0;
623 static void
624 snooper(GdkEvent *event, gpointer data) { 
625     if(inkscape_mapalt())  /* returns the map of the keyboard modifier to map to Alt, zero if no mapping */
626     {
627         GdkModifierType mapping=(GdkModifierType)inkscape_mapalt();
628         switch (event->type) {
629             case GDK_MOTION_NOTIFY:
630                 if(event->motion.state & mapping) {
631                     event->motion.state|=GDK_MOD1_MASK;
632                 }
633                 break;       
634             case GDK_BUTTON_PRESS:
635                 if(event->button.state & mapping) {
636                     event->button.state|=GDK_MOD1_MASK;
637                 }
638                 break;       
639              case GDK_KEY_PRESS:
640                  if(event->key.state & mapping) {
641                      event->key.state|=GDK_MOD1_MASK;
642                  }
643                  break;                
644         default:
645             break;
646         }
647     }
648     gtk_main_do_event (event);
651 int
652 sp_main_gui(int argc, char const **argv)
654     Gtk::Main main_instance (&argc, const_cast<char ***>(&argv));
656     GSList *fl = NULL;
657     int retVal = sp_common_main( argc, argv, &fl );
658     g_return_val_if_fail(retVal == 0, 1);
660     inkscape_gtk_stock_init();
662     gdk_event_handler_set((GdkEventFunc)snooper, NULL, NULL);
664     Inkscape::Debug::log_display_config();
666     /* Set default icon */
667     gchar *filename = (gchar *) g_build_filename (INKSCAPE_APPICONDIR, "inkscape.png", NULL);
668     if (Inkscape::IO::file_test(filename, (GFileTest)(G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK))) {
669         gtk_window_set_default_icon_from_file(filename, NULL);
670     }
671     g_free (filename);
672     filename = 0;
674     gboolean create_new = TRUE;
676     /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
677     inkscape_application_init(argv[0], true);
679     while (fl) {
680         if (sp_file_open((gchar *)fl->data,NULL)) {
681             create_new=FALSE;
682         }
683         fl = g_slist_remove(fl, fl->data);
684     }
685     if (create_new) {
686         sp_file_new_default();
687     }
689     Glib::signal_idle().connect(sigc::ptr_fun(&Inkscape::CmdLineAction::idle));
690     main_instance.run();
692 #ifdef WIN32
693     //We might not need anything here
694     //sp_win32_finish(); <-- this is a NOP func
695 #endif
697     return 0;
700 int
701 sp_main_console(int argc, char const **argv)
703     /* We are started in text mode */
705     /* Do this g_type_init(), so that we can use Xft/Freetype2 (Pango)
706      * in a non-Gtk environment.  Used in libnrtype's
707      * FontInstance.cpp and FontFactory.cpp.
708      * http://mail.gnome.org/archives/gtk-list/2003-December/msg00063.html
709      */
710     g_type_init();
711     char **argv2 = const_cast<char **>(argv);
712     gtk_init_check( &argc, &argv2 );
713     //setlocale(LC_ALL, "");
715     GSList *fl = NULL;
716     int retVal = sp_common_main( argc, argv, &fl );
717     g_return_val_if_fail(retVal == 0, 1);
719     if (fl == NULL) {
720         g_print("Nothing to do!\n");
721         exit(0);
722     }
724     inkscape_application_init(argv[0], false);
726     while (fl) {
727         SPDocument *doc;
729         doc = Inkscape::Extension::open(NULL, (gchar *)fl->data);
730         if (doc == NULL) {
731             doc = Inkscape::Extension::open(Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), (gchar *)fl->data);
732         }
733         if (doc == NULL) {
734             g_warning("Specified document %s cannot be opened (is it valid SVG file?)", (gchar *) fl->data);
735         } else {
736             if (sp_vacuum_defs) {
737                 vacuum_document(doc);
738             }
739             if (sp_vacuum_defs && !sp_export_svg) {
740                 // save under the name given in the command line
741                 sp_repr_save_file(doc->rdoc, (gchar *)fl->data, SP_SVG_NS_URI);
742             }
743             if (sp_global_printer) {
744                 sp_print_document_to_file(doc, sp_global_printer);
745             }
746             if (sp_export_png || sp_export_id || sp_export_area_drawing) {
747                 sp_do_export_png(doc);
748             }
749             if (sp_export_svg) {
750                 Inkscape::XML::Document *rdoc;
751                 Inkscape::XML::Node *repr;
752                 rdoc = sp_repr_document_new("svg:svg");
753                 repr = rdoc->root();
754                 repr = sp_document_root(doc)->updateRepr(repr, SP_OBJECT_WRITE_BUILD);
755                 sp_repr_save_file(repr->document(), sp_export_svg, SP_SVG_NS_URI);
756             }
757             if (sp_export_ps) {
758                 do_export_ps(doc, sp_export_ps, "image/x-postscript");
759             }
760             if (sp_export_eps) {
761                 do_export_ps(doc, sp_export_eps, "image/x-e-postscript");
762             }
763             if (sp_export_pdf) {
764                 do_export_pdf(doc, sp_export_pdf, "application/pdf");
765             }
766             if (sp_query_width || sp_query_height) {
767                 do_query_dimension (doc, true, sp_query_width? NR::X : NR::Y, sp_query_id);
768             } else if (sp_query_x || sp_query_y) {
769                 do_query_dimension (doc, false, sp_query_x? NR::X : NR::Y, sp_query_id);
770             }
771         }
773         fl = g_slist_remove(fl, fl->data);
774     }
776     inkscape_unref();
778     return 0;
781 static void
782 do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id)
784     SPObject *o = NULL;
786     if (id) {
787         o = doc->getObjectById(id);
788         if (o) {
789             if (!SP_IS_ITEM (o)) {
790                 g_warning("Object with id=\"%s\" is not a visible item. Cannot query dimensions.", id);
791                 return;
792             }
793         } else {
794             g_warning("Object with id=\"%s\" is not found. Cannot query dimensions.", id);
795             return;
796         }
797     } else {
798         o = SP_DOCUMENT_ROOT(doc);
799     }
801     if (o) {
802         sp_document_ensure_up_to_date (doc);
803         SPItem *item = ((SPItem *) o);
805         // "true" SVG bbox for scripting
806         NR::Maybe<NR::Rect> area = item->getBounds(sp_item_i2doc_affine(item));
807         if (area) {
808             Inkscape::SVGOStringStream os;
809             if (extent) {
810                 os << area->extent(axis);
811             } else {
812                 os << area->min()[axis];
813             }
814             g_print ("%s", os.str().c_str());
815         } else {
816             g_print("0");
817         }
818     }
822 static void
823 sp_do_export_png(SPDocument *doc)
825     const gchar *filename = NULL;
826     gdouble dpi = 0.0;
828     if (sp_export_use_hints && (!sp_export_id && !sp_export_area_drawing)) {
829         g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored.");
830     }
832     GSList *items = NULL;
834     NRRect area;
835     if (sp_export_id || sp_export_area_drawing) {
837         SPObject *o = NULL;
838         SPObject *o_area = NULL;
839         if (sp_export_id && sp_export_area_drawing) {
840             o = doc->getObjectById(sp_export_id);
841             o_area = SP_DOCUMENT_ROOT (doc);
842         } else if (sp_export_id) {
843             o = doc->getObjectById(sp_export_id);
844             o_area = o;
845         } else if (sp_export_area_drawing) {
846             o = SP_DOCUMENT_ROOT (doc);
847             o_area = o;
848         } 
850         if (o) {
851             if (!SP_IS_ITEM (o)) {
852                 g_warning("Object with id=\"%s\" is not a visible item. Nothing exported.", sp_export_id);
853                 return;
854             }
856             items = g_slist_prepend (items, SP_ITEM(o));
858             if (sp_export_id_only) {
859                 g_print("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id);
860             }
862             if (sp_export_use_hints) {
864                 // retrieve export filename hint
865                 const gchar *fn_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-filename");
866                 if (fn_hint) {
867                     if (sp_export_png) {
868                         g_warning ("Using export filename from the command line (--export-png). Filename hint %s is ignored.", fn_hint);
869                         filename = sp_export_png;
870                     } else {
871                         filename = fn_hint;
872                     }
873                 } else {
874                     g_warning ("Export filename hint not found for the object.");
875                     filename = sp_export_png;
876                 }
878                 // retrieve export dpi hints
879                 const gchar *dpi_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
880                 if (dpi_hint) {
881                     if (sp_export_dpi || sp_export_width || sp_export_height) {
882                         g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint);
883                     } else {
884                         dpi = atof(dpi_hint);
885                     }
886                 } else {
887                     g_warning ("Export DPI hint not found for the object.");
888                 }
890             }
892             // write object bbox to area
893             sp_document_ensure_up_to_date (doc);
894             sp_item_invoke_bbox((SPItem *) o_area, &area, sp_item_i2r_affine((SPItem *) o_area), TRUE);
895         } else {
896             g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
897             return;
898         }
899     }
900     
901     if (sp_export_area) {
902         /* Try to parse area (given in SVG pixels) */
903         if (!sscanf(sp_export_area, "%lg:%lg:%lg:%lg", &area.x0, &area.y0, &area.x1, &area.y1) == 4) {
904             g_warning("Cannot parse export area '%s'; use 'x0:y0:x1:y1'. Nothing exported.", sp_export_area);
905             return;
906         }
907         if ((area.x0 >= area.x1) || (area.y0 >= area.y1)) {
908             g_warning("Export area '%s' has negative width or height. Nothing exported.", sp_export_area);
909             return;
910         }
911     } else if (sp_export_area_canvas || !(sp_export_id || sp_export_area_drawing)) {
912         /* Export the whole canvas */
913         sp_document_ensure_up_to_date (doc);
914         area.x0 = SP_ROOT(doc->root)->x.computed;
915         area.y0 = SP_ROOT(doc->root)->y.computed;
916         area.x1 = area.x0 + sp_document_width (doc);
917         area.y1 = area.y0 + sp_document_height (doc);
918     }
920     // set filename and dpi from options, if not yet set from the hints
921     if (!filename) {
922         if (!sp_export_png) {
923             g_warning ("No export filename given and no filename hint. Nothing exported.");
924             return;
925         }
926         filename = sp_export_png;
927     }
929     if (sp_export_dpi && dpi == 0.0) {
930         dpi = atof(sp_export_dpi);
931         if ((dpi < 0.1) || (dpi > 10000.0)) {
932             g_warning("DPI value %s out of range [0.1 - 10000.0]. Nothing exported.", sp_export_dpi);
933             return;
934         }
935         g_print("DPI: %g\n", dpi);
936     }
938     if (sp_export_area_snap) {
939         area.x0 = std::floor (area.x0);
940         area.y0 = std::floor (area.y0);
941         area.x1 = std::ceil (area.x1);
942         area.y1 = std::ceil (area.y1);
943     }
945     // default dpi
946     if (dpi == 0.0)
947         dpi = PX_PER_IN;
949     gint width = 0;
950     gint height = 0;
952     if (sp_export_width) {
953         width = atoi(sp_export_width);
954         if ((width < 1) || (width > 65536)) {
955             g_warning("Export width %d out of range (1 - 65536). Nothing exported.", width);
956             return;
957         }
958         dpi = (gdouble) width * PX_PER_IN / (area.x1 - area.x0);
959     }
961     if (sp_export_height) {
962         height = atoi(sp_export_height);
963         if ((height < 1) || (height > 65536)) {
964             g_warning("Export height %d out of range (1 - 65536). Nothing exported.", width);
965             return;
966         }
967         dpi = (gdouble) height * PX_PER_IN / (area.y1 - area.y0);
968     }
970     if (!sp_export_width) {
971         width = (gint) ((area.x1 - area.x0) * dpi / PX_PER_IN + 0.5);
972     }
974     if (!sp_export_height) {
975         height = (gint) ((area.y1 - area.y0) * dpi / PX_PER_IN + 0.5);
976     }
978     guint32 bgcolor = 0x00000000;
979     if (sp_export_background) {
980         // override the page color
981         bgcolor = sp_svg_read_color(sp_export_background, 0xffffff00);
982         bgcolor |= 0xff; // default is no opacity
983     } else {
984         // read from namedview
985         Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
986         if (nv && nv->attribute("pagecolor"))
987             bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
988         if (nv && nv->attribute("inkscape:pageopacity"))
989             bgcolor |= SP_COLOR_F_TO_U(sp_repr_get_double_attribute (nv, "inkscape:pageopacity", 1.0));
990     }
992     if (sp_export_background_opacity) {
993         // override opacity
994         gfloat value;
995         if (sp_svg_number_read_f (sp_export_background_opacity, &value)) {
996             if (value > 1.0) {
997                 value = CLAMP (value, 1.0f, 255.0f);
998                 bgcolor &= (guint32) 0xffffff00;
999                 bgcolor |= (guint32) floor(value);
1000             } else {
1001                 value = CLAMP (value, 0.0f, 1.0f);
1002                 bgcolor &= (guint32) 0xffffff00;
1003                 bgcolor |= SP_COLOR_F_TO_U(value);
1004             }
1005         }
1006     }
1008     g_print("Background RRGGBBAA: %08x\n", bgcolor);
1010     g_print("Area %g:%g:%g:%g exported to %d x %d pixels (%g dpi)\n", area.x0, area.y0, area.x1, area.y1, width, height, dpi);
1012     g_print("Bitmap saved as: %s\n", filename);
1014     if ((width >= 1) && (height >= 1) && (width < 65536) && (height < 65536)) {
1015         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);
1016     } else {
1017         g_warning("Calculated bitmap dimensions %d %d are out of range (1 - 65535). Nothing exported.", width, height);
1018     }
1020     g_slist_free (items);
1024 /**
1025  *  Perform an export of either PS or EPS.
1026  *
1027  *  \param doc Document to export.
1028  *  \param uri URI to export to.
1029  *  \param mime MIME type to export as.
1030  */
1032 static void do_export_ps(SPDocument* doc, gchar const* uri, char const* mime)
1034     Inkscape::Extension::DB::OutputList o;
1035     Inkscape::Extension::db.get_output_list(o);
1036     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1037     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1038         i++;
1039     }
1041     if (i == o.end())
1042     {
1043         g_warning ("Could not find an extension to export this file.");
1044         return;
1045     }
1047     bool old_text_to_path = false;
1048     bool old_font_embedded = false;
1049     bool old_bbox_page = false;
1051     try {
1052         old_text_to_path = (*i)->get_param_bool("textToPath");
1053         (*i)->set_param_bool("textToPath", sp_export_text_to_path);
1054     }
1055     catch (...) {
1056         g_warning ("Could not set export-text-to-path option for this export.");
1057     }
1059     try {
1060         old_font_embedded = (*i)->get_param_bool("fontEmbedded");
1061         (*i)->set_param_bool("fontEmbedded", sp_export_font);
1062     }
1063     catch (...) {
1064         g_warning ("Could not set export-font option for this export.");
1065     }
1067     try {
1068         old_bbox_page = (*i)->get_param_bool("pageBoundingBox");
1069         (*i)->set_param_bool("pageBoundingBox", sp_export_bbox_page);
1070     }
1071     catch (...) {
1072         g_warning ("Could not set export-bbox-page option for this export.");
1073     }
1075     (*i)->save(doc, uri);
1077     try {
1078         (*i)->set_param_bool("textToPath", old_text_to_path);
1079         (*i)->set_param_bool("fontEmbedded", old_font_embedded);
1080         (*i)->set_param_bool("pageBoundingBox", old_bbox_page);
1081     }
1082     catch (...) {
1084     }
1087 /**
1088  *  Perform a PDF export
1089  *
1090  *  \param doc Document to export.
1091  *  \param uri URI to export to.
1092  *  \param mime MIME type to export as.
1093  */
1095 static void do_export_pdf(SPDocument* doc, gchar const* uri, char const* mime)
1097     Inkscape::Extension::DB::OutputList o;
1098     Inkscape::Extension::db.get_output_list(o);
1099     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1100     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1101         i++;
1102     }
1104     if (i == o.end())
1105     {
1106         g_warning ("Could not find an extension to export this file.");
1107         return;
1108     }
1110     (*i)->save(doc, uri);
1113 #ifdef WIN32
1114 bool replaceArgs( int& argc, char**& argv )
1116     bool worked = false;
1118 #ifdef REPLACEARGS_DEBUG
1119     MessageBoxA( NULL, "GetCommandLineW() getting called", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1120 #endif // REPLACEARGS_DEBUG
1122     wchar_t* line = GetCommandLineW();
1123     if ( line )
1124     {
1125 #ifdef REPLACEARGS_DEBUG
1126         {
1127             gchar* utf8Line = g_utf16_to_utf8( (gunichar2*)line, -1, NULL, NULL, NULL );
1128             if ( utf8Line )
1129             {
1130                 gchar *safe = Inkscape::IO::sanitizeString(utf8Line);
1131                 {
1132                     char tmp[strlen(safe) + 32];
1133                     snprintf( tmp, sizeof(tmp), "GetCommandLineW() = '%s'", safe );
1134                     MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1135                 }
1136             }
1137         }
1138 #endif // REPLACEARGS_DEBUG
1140         int numArgs = 0;
1141         wchar_t** parsed = CommandLineToArgvW( line, &numArgs );
1143 #ifdef REPLACEARGS_ANSI
1144 // test code for trying things on Win95/98/ME
1145         if ( !parsed )
1146         {
1147 #ifdef REPLACEARGS_DEBUG
1148             MessageBoxA( NULL, "Unable to process command-line. Faking it", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1149 #endif // REPLACEARGS_DEBUG
1150             int lineLen = wcslen(line) + 1;
1151             wchar_t* lineDup = new wchar_t[lineLen];
1152             wcsncpy( lineDup, line, lineLen );
1154             int pos = 0;
1155             bool inQuotes = false;
1156             bool inWhitespace = true;
1157             std::vector<int> places;
1158             while ( lineDup[pos] )
1159             {
1160                 if ( inQuotes )
1161                 {
1162                     if ( lineDup[pos] == L'"' )
1163                     {
1164                         inQuotes = false;
1165                     }
1166                 }
1167                 else if ( lineDup[pos] == L'"' )
1168                 {
1169                     inQuotes = true;
1170                     inWhitespace = false;
1171                     places.push_back(pos);
1172                 }
1173                 else if ( lineDup[pos] == L' ' || lineDup[pos] == L'\t' )
1174                 {
1175                     if ( !inWhitespace )
1176                     {
1177                         inWhitespace = true;
1178                         lineDup[pos] = 0;
1179                     }
1180                 }
1181                 else if ( inWhitespace && (lineDup[pos] != L' ' && lineDup[pos] != L'\t') )
1182                 {
1183                     inWhitespace = false;
1184                     places.push_back(pos);
1185                 }
1186                 else
1187                 {
1188                     // consume
1189                 }
1190                 pos++;
1191             }
1192 #ifdef REPLACEARGS_DEBUG
1193             {
1194                 char tmp[256];
1195                 snprintf( tmp, sizeof(tmp), "Counted %d args", places.size() );
1196                 MessageBoxA( NULL, tmp, "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1197             }
1198 #endif // REPLACEARGS_DEBUG
1200             wchar_t** block = new wchar_t*[places.size()];
1201             int i = 0;
1202             for ( std::vector<int>::iterator it = places.begin(); it != places.end(); it++ )
1203             {
1204                 block[i++] = &lineDup[*it];
1205             }
1206             parsed = block;
1207             numArgs = places.size();
1208         }
1209 #endif // REPLACEARGS_ANSI
1211         if ( parsed )
1212         {
1213             std::vector<wchar_t*>expandedArgs;
1214             if ( numArgs > 0 )
1215             {
1216                 expandedArgs.push_back( parsed[0] );
1217             }
1219             for ( int i1 = 1; i1 < numArgs; i1++ )
1220             {
1221                 bool wildcarded = (wcschr(parsed[i1], L'?') != NULL) || (wcschr(parsed[i1], L'*') != NULL);
1222                 wildcarded &= parsed[i1][0] != L'"';
1223                 wildcarded &= parsed[i1][0] != L'-';
1224                 if ( wildcarded )
1225                 {
1226 #ifdef REPLACEARGS_ANSI
1227                     WIN32_FIND_DATAA data = {0};
1228 #else
1229                     WIN32_FIND_DATAW data = {0};
1230 #endif // REPLACEARGS_ANSI
1232                     int baseLen = wcslen(parsed[i1]) + 2;
1233                     wchar_t* base = new wchar_t[baseLen];
1234                     wcsncpy( base, parsed[i1], baseLen );
1235                     wchar_t* last = wcsrchr( base, L'\\' );
1236                     if ( last )
1237                     {
1238                         last[1] = 0;
1239                     }
1240                     else
1241                     {
1242                         base[0] = 0;
1243                     }
1244                     baseLen = wcslen( base );
1246 #ifdef REPLACEARGS_ANSI
1247                     char target[MAX_PATH];
1248                     if ( WideCharToMultiByte( CP_ACP, 0, parsed[i1], -1, target, sizeof(target), NULL, NULL) )
1249                     {
1250                         HANDLE hf = FindFirstFileA( target, &data );
1251 #else
1252                         HANDLE hf = FindFirstFileW( parsed[i1], &data );
1253 #endif // REPLACEARGS_ANSI
1254                         if ( hf != INVALID_HANDLE_VALUE )
1255                         {
1256                             BOOL found = TRUE;
1257                             do
1258                             {
1259 #ifdef REPLACEARGS_ANSI
1260                                 int howMany = MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, NULL, 0 );
1261                                 if ( howMany > 0 )
1262                                 {
1263                                     howMany += baseLen;
1264                                     wchar_t* tmp = new wchar_t[howMany + 1];
1265                                     wcsncpy( tmp, base, howMany + 1 );
1266                                     MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, tmp + baseLen, howMany + 1 - baseLen );
1267                                     expandedArgs.push_back( tmp );
1268                                     found = FindNextFileA( hf, &data );
1269                                 }
1270 #else
1271                                 int howMany = wcslen(data.cFileName) + baseLen;
1272                                 wchar_t* tmp = new wchar_t[howMany + 1];
1273                                 wcsncpy( tmp, base, howMany + 1 );
1274                                 wcsncat( tmp, data.cFileName, howMany + 1 );
1275                                 expandedArgs.push_back( tmp );
1276                                 found = FindNextFileW( hf, &data );
1277 #endif // REPLACEARGS_ANSI
1278                             } while ( found );
1280                             FindClose( hf );
1281                         }
1282                         else
1283                         {
1284                             expandedArgs.push_back( parsed[i1] );
1285                         }
1286 #ifdef REPLACEARGS_ANSI
1287                     }
1288 #endif // REPLACEARGS_ANSI
1290                     delete[] base;
1291                 }
1292                 else
1293                 {
1294                     expandedArgs.push_back( parsed[i1] );
1295                 }
1296             }
1298             {
1299                 wchar_t** block = new wchar_t*[expandedArgs.size()];
1300                 int iz = 0;
1301                 for ( std::vector<wchar_t*>::iterator it = expandedArgs.begin(); it != expandedArgs.end(); it++ )
1302                 {
1303                     block[iz++] = *it;
1304                 }
1305                 parsed = block;
1306                 numArgs = expandedArgs.size();
1307             }
1309             std::vector<gchar*> newArgs;
1310             for ( int i = 0; i < numArgs; i++ )
1311             {
1312                 gchar* replacement = g_utf16_to_utf8( (gunichar2*)parsed[i], -1, NULL, NULL, NULL );
1313                 if ( replacement )
1314                 {
1315 #ifdef REPLACEARGS_DEBUG
1316                     gchar *safe2 = Inkscape::IO::sanitizeString(replacement);
1318                     if ( safe2 )
1319                     {
1320                         {
1321                             char tmp[1024];
1322                             snprintf( tmp, sizeof(tmp), "    [%2d] = '%s'", i, safe2 );
1323                             MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1324                         }
1325                         g_free( safe2 );
1326                     }
1327 #endif // REPLACEARGS_DEBUG
1329                     newArgs.push_back( replacement );
1330                 }
1331                 else
1332                 {
1333                     newArgs.push_back( blankParam );
1334                 }
1335             }
1337             // Now push our munged params to be the new argv and argc
1338             {
1339                 char** block = new char*[newArgs.size()];
1340                 int iz = 0;
1341                 for ( std::vector<char*>::iterator it = newArgs.begin(); it != newArgs.end(); it++ )
1342                 {
1343                     block[iz++] = *it;
1344                 }
1345                 argv = block;
1346                 argc = newArgs.size();
1347                 worked = true;
1348             }
1349         }
1350 #ifdef REPLACEARGS_DEBUG
1351         else
1352         {
1353             MessageBoxA( NULL, "Unable to process command-line", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1354         }
1355 #endif // REPLACEARGS_DEBUG
1356     }
1357 #ifdef REPLACEARGS_DEBUG
1358     else
1359     {
1360         {
1361             MessageBoxA( NULL,  "Unable to fetch result from GetCommandLineW()", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1362         }
1364         char* line2 = GetCommandLineA();
1365         if ( line2 )
1366         {
1367             gchar *safe = Inkscape::IO::sanitizeString(line2);
1368             {
1369                 {
1370                     char tmp[strlen(safe) + 32];
1371                     snprintf( tmp, sizeof(tmp), "GetCommandLineA() = '%s'", safe );
1372                     MessageBoxA( NULL, tmp, "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1373                 }
1374             }
1375         }
1376         else
1377         {
1378             MessageBoxA( NULL, "Unable to fetch result from GetCommandLineA()", "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1379         }
1380     }
1381 #endif // REPLACEARGS_DEBUG
1383     return worked;
1385 #endif // WIN32
1387 static GSList *
1388 sp_process_args(poptContext ctx)
1390     GSList *fl = NULL;
1392     gint a;
1393     while ((a = poptGetNextOpt(ctx)) >= 0) {
1394         switch (a) {
1395             case SP_ARG_FILE: {
1396                 gchar const *fn = poptGetOptArg(ctx);
1397                 if (fn != NULL) {
1398                     fl = g_slist_append(fl, g_strdup(fn));
1399                 }
1400                 break;
1401             }
1402             case SP_ARG_VERSION: {
1403                 printf("Inkscape %s (%s)\n", INKSCAPE_VERSION, __DATE__);
1404                 exit(0);
1405                 break;
1406             }
1407             case SP_ARG_EXTENSIONDIR: {
1408                 printf("%s\n", INKSCAPE_EXTENSIONDIR);
1409                 exit(0);
1410                 break;
1411             }
1412             case SP_ARG_VERB_LIST: {
1413                 // This really shouldn't go here, we should init the app.
1414                 // But, since we're just exiting in this path, there is
1415                 // no harm, and this is really a better place to put
1416                 // everything else.
1417                 Inkscape::Extension::init();
1418                 Inkscape::Verb::list();
1419                 exit(0);
1420                 break;
1421             }
1422             case SP_ARG_VERB:
1423             case SP_ARG_SELECT: {
1424                 gchar const *arg = poptGetOptArg(ctx);
1425                 if (arg != NULL) {
1426                     // printf("Adding in: %s\n", arg);
1427                     new Inkscape::CmdLineAction((a == SP_ARG_VERB), arg);
1428                 }
1429                 break;
1430             }
1431             default: {
1432                 break;
1433             }
1434         }
1435     }
1437     gchar const ** const args = poptGetArgs(ctx);
1438     if (args != NULL) {
1439         for (unsigned i = 0; args[i] != NULL; i++) {
1440             fl = g_slist_append(fl, g_strdup(args[i]));
1441         }
1442     }
1444     return fl;
1448 /*
1449   Local Variables:
1450   mode:c++
1451   c-file-style:"stroustrup"
1452   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1453   indent-tabs-mode:nil
1454   fill-column:99
1455   End:
1456 */
1457 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :