Code

Oops - obviously the previous fix didn't work outside Windows
[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 // This has to be included prior to anything that includes setjmp.h, it croaks otherwise
32 #include <png.h>
34 #include <gtk/gtkmessagedialog.h>
36 #ifdef HAVE_IEEEFP_H
37 #include <ieeefp.h>
38 #endif
39 #include <cstring>
40 #include <string>
41 #include <locale.h>
42 #include <stdlib.h>
44 #include <popt.h>
45 #ifndef POPT_TABLEEND
46 #define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL }
47 #endif /* Not def: POPT_TABLEEND */
49 #include <libxml/tree.h>
50 #include <glib.h>
51 #include <glib/gprintf.h>
52 #include <glib-object.h>
53 #include <gtk/gtk.h>
54 #include <gtk/gtkmain.h>
55 #include <gtk/gtksignal.h>
56 #include <gtk/gtkwindow.h>
57 #include <gtk/gtkbox.h>
59 #include "gc-core.h"
61 #ifdef AND
62 #undef AND
63 #endif
65 #include "macros.h"
66 #include "file.h"
67 #include "document.h"
68 #include "sp-object.h"
69 #include "interface.h"
70 #include "print.h"
71 #include "color.h"
72 #include "sp-item.h"
73 #include "sp-root.h"
74 #include "unit-constants.h"
76 #include "svg/svg.h"
77 #include "svg/svg-color.h"
78 #include "svg/stringstream.h"
80 #include "inkscape-private.h"
81 #include "inkscape-version.h"
83 #include "sp-namedview.h"
84 #include "sp-guide.h"
85 #include "sp-object-repr.h"
86 #include "xml/repr.h"
88 #include "io/sys.h"
90 #include "debug/logger.h"
91 #include "debug/log-display-config.h"
93 #include "helper/png-write.h"
94 #include "helper/geom.h"
96 #include <extension/extension.h>
97 #include <extension/system.h>
98 #include <extension/db.h>
99 #include <extension/output.h>
100 #include <extension/input.h>
102 #ifdef WIN32
103 #include "registrytool.h"
104 #include "extension/internal/win32.h"
105 using Inkscape::Extension::Internal::PrintWin32;
106 #endif // WIN32
108 #include "extension/init.h"
110 #include <glibmm/i18n.h>
111 #include <gtkmm/main.h>
113 #ifndef HAVE_BIND_TEXTDOMAIN_CODESET
114 #define bind_textdomain_codeset(p,c)
115 #endif
117 #include "application/application.h"
118 #include "main-cmdlineact.h"
119 #include "widgets/icon.h"
120 #include "ui/widget/panel.h"
122 #include <errno.h>
124 enum {
125     SP_ARG_NONE,
126     SP_ARG_NOGUI,
127     SP_ARG_GUI,
128     SP_ARG_FILE,
129     SP_ARG_PRINT,
130     SP_ARG_EXPORT_PNG,
131     SP_ARG_EXPORT_DPI,
132     SP_ARG_EXPORT_AREA,
133     SP_ARG_EXPORT_AREA_DRAWING,
134     SP_ARG_EXPORT_AREA_PAGE,
135     SP_ARG_EXPORT_AREA_SNAP,
136     SP_ARG_EXPORT_WIDTH,
137     SP_ARG_EXPORT_HEIGHT,
138     SP_ARG_EXPORT_ID,
139     SP_ARG_EXPORT_ID_ONLY,
140     SP_ARG_EXPORT_USE_HINTS,
141     SP_ARG_EXPORT_BACKGROUND,
142     SP_ARG_EXPORT_BACKGROUND_OPACITY,
143     SP_ARG_EXPORT_SVG,
144     SP_ARG_EXPORT_PS,
145     SP_ARG_EXPORT_EPS,
146     SP_ARG_EXPORT_PDF,
147     SP_ARG_EXPORT_LATEX,
148 #ifdef WIN32
149     SP_ARG_EXPORT_EMF,
150 #endif //WIN32
151     SP_ARG_EXPORT_TEXT_TO_PATH,
152     SP_ARG_EXPORT_IGNORE_FILTERS,
153     SP_ARG_EXTENSIONDIR,
154     SP_ARG_QUERY_X,
155     SP_ARG_QUERY_Y,
156     SP_ARG_QUERY_WIDTH,
157     SP_ARG_QUERY_HEIGHT,
158     SP_ARG_QUERY_ALL,
159     SP_ARG_QUERY_ID,
160     SP_ARG_SHELL,
161     SP_ARG_VERSION,
162     SP_ARG_VACUUM_DEFS,
163     SP_ARG_VERB_LIST,
164     SP_ARG_VERB,
165     SP_ARG_SELECT,
166     SP_ARG_LAST
167 };
169 int sp_main_gui(int argc, char const **argv);
170 int sp_main_console(int argc, char const **argv);
171 static void sp_do_export_png(SPDocument *doc);
172 static void do_export_ps_pdf(SPDocument* doc, gchar const* uri, char const *mime);
173 #ifdef WIN32
174 static void do_export_emf(SPDocument* doc, gchar const* uri, char const *mime);
175 #endif //WIN32
176 static void do_query_dimension (SPDocument *doc, bool extent, Geom::Dim2 const axis, const gchar *id);
177 static void do_query_all (SPDocument *doc);
178 static void do_query_all_recurse (SPObject *o);
180 static gchar *sp_global_printer = NULL;
181 static gchar *sp_export_png = NULL;
182 static gchar *sp_export_dpi = NULL;
183 static gchar *sp_export_area = NULL;
184 static gboolean sp_export_area_drawing = FALSE;
185 static gboolean sp_export_area_page = FALSE;
186 static gboolean sp_export_latex = FALSE;
187 static gchar *sp_export_width = NULL;
188 static gchar *sp_export_height = NULL;
189 static gchar *sp_export_id = NULL;
190 static gchar *sp_export_background = NULL;
191 static gchar *sp_export_background_opacity = NULL;
192 static gboolean sp_export_area_snap = FALSE;
193 static gboolean sp_export_use_hints = FALSE;
194 static gboolean sp_export_id_only = FALSE;
195 static gchar *sp_export_svg = NULL;
196 static gchar *sp_export_ps = NULL;
197 static gchar *sp_export_eps = NULL;
198 static gchar *sp_export_pdf = NULL;
199 #ifdef WIN32
200 static gchar *sp_export_emf = NULL;
201 #endif //WIN32
202 static gboolean sp_export_text_to_path = FALSE;
203 static gboolean sp_export_ignore_filters = FALSE;
204 static gboolean sp_export_font = FALSE;
205 static gboolean sp_query_x = FALSE;
206 static gboolean sp_query_y = FALSE;
207 static gboolean sp_query_width = FALSE;
208 static gboolean sp_query_height = FALSE;
209 static gboolean sp_query_all = FALSE;
210 static gchar *sp_query_id = NULL;
211 static int sp_new_gui = FALSE;
212 static gboolean sp_shell = FALSE;
213 static gboolean sp_vacuum_defs = FALSE;
215 static gchar *sp_export_png_utf8 = NULL;
216 static gchar *sp_export_svg_utf8 = NULL;
217 static gchar *sp_global_printer_utf8 = NULL;
220 /**
221  *  Reset variables to default values.
222  */
223 static void resetCommandlineGlobals() {
224         sp_global_printer = NULL;
225         sp_export_png = NULL;
226         sp_export_dpi = NULL;
227         sp_export_area = NULL;
228         sp_export_area_drawing = FALSE;
229         sp_export_area_page = FALSE;
230         sp_export_latex = FALSE;
231         sp_export_width = NULL;
232         sp_export_height = NULL;
233         sp_export_id = NULL;
234         sp_export_background = NULL;
235         sp_export_background_opacity = NULL;
236         sp_export_area_snap = FALSE;
237         sp_export_use_hints = FALSE;
238         sp_export_id_only = FALSE;
239         sp_export_svg = NULL;
240         sp_export_ps = NULL;
241         sp_export_eps = NULL;
242         sp_export_pdf = NULL;
243 #ifdef WIN32
244         sp_export_emf = NULL;
245 #endif //WIN32
246         sp_export_text_to_path = FALSE;
247         sp_export_ignore_filters = FALSE;
248         sp_export_font = FALSE;
249         sp_query_x = FALSE;
250         sp_query_y = FALSE;
251         sp_query_width = FALSE;
252         sp_query_height = FALSE;
253         sp_query_all = FALSE;
254         sp_query_id = NULL;
255         sp_vacuum_defs = FALSE;
257         sp_export_png_utf8 = NULL;
258         sp_export_svg_utf8 = NULL;
259         sp_global_printer_utf8 = NULL;
262 #ifdef WIN32
263 static bool replaceArgs( int& argc, char**& argv );
264 #endif
265 static GSList *sp_process_args(poptContext ctx);
266 struct poptOption options[] = {
267     {"version", 'V',
268      POPT_ARG_NONE, NULL, SP_ARG_VERSION,
269      N_("Print the Inkscape version number"),
270      NULL},
272     {"without-gui", 'z',
273      POPT_ARG_NONE, NULL, SP_ARG_NOGUI,
274      N_("Do not use X server (only process files from console)"),
275      NULL},
277     {"with-gui", 'g',
278      POPT_ARG_NONE, NULL, SP_ARG_GUI,
279      N_("Try to use X server (even if $DISPLAY is not set)"),
280      NULL},
282     {"file", 'f',
283      POPT_ARG_STRING, NULL, SP_ARG_FILE,
284      N_("Open specified document(s) (option string may be excluded)"),
285      N_("FILENAME")},
287     {"print", 'p',
288      POPT_ARG_STRING, &sp_global_printer, SP_ARG_PRINT,
289      N_("Print document(s) to specified output file (use '| program' for pipe)"),
290      N_("FILENAME")},
292     {"export-png", 'e',
293      POPT_ARG_STRING, &sp_export_png, SP_ARG_EXPORT_PNG,
294      N_("Export document to a PNG file"),
295      N_("FILENAME")},
297     {"export-dpi", 'd',
298      POPT_ARG_STRING, &sp_export_dpi, SP_ARG_EXPORT_DPI,
299      N_("Resolution for exporting to bitmap and for rasterization of filters in PS/EPS/PDF (default 90)"),
300      N_("DPI")},
302     {"export-area", 'a',
303      POPT_ARG_STRING, &sp_export_area, SP_ARG_EXPORT_AREA,
304      N_("Exported area in SVG user units (default is the page; 0,0 is lower-left corner)"),
305      N_("x0:y0:x1:y1")},
307     {"export-area-drawing", 'D',
308      POPT_ARG_NONE, &sp_export_area_drawing, SP_ARG_EXPORT_AREA_DRAWING,
309      N_("Exported area is the entire drawing (not page)"),
310      NULL},
312     {"export-area-page", 'C',
313      POPT_ARG_NONE, &sp_export_area_page, SP_ARG_EXPORT_AREA_PAGE,
314      N_("Exported area is the entire page"),
315      NULL},
317     {"export-area-snap", 0,
318      POPT_ARG_NONE, &sp_export_area_snap, SP_ARG_EXPORT_AREA_SNAP,
319      N_("Snap the bitmap export area outwards to the nearest integer values (in SVG user units)"),
320      NULL},
322     {"export-width", 'w',
323      POPT_ARG_STRING, &sp_export_width, SP_ARG_EXPORT_WIDTH,
324      N_("The width of exported bitmap in pixels (overrides export-dpi)"),
325      N_("WIDTH")},
327     {"export-height", 'h',
328      POPT_ARG_STRING, &sp_export_height, SP_ARG_EXPORT_HEIGHT,
329      N_("The height of exported bitmap in pixels (overrides export-dpi)"),
330      N_("HEIGHT")},
332     {"export-id", 'i',
333      POPT_ARG_STRING, &sp_export_id, SP_ARG_EXPORT_ID,
334      N_("The ID of the object to export"),
335      N_("ID")},
337     {"export-id-only", 'j',
338      POPT_ARG_NONE, &sp_export_id_only, SP_ARG_EXPORT_ID_ONLY,
339      // TRANSLATORS: this means: "Only export the object whose id is given in --export-id".
340      //  See "man inkscape" for details.
341      N_("Export just the object with export-id, hide all others (only with export-id)"),
342      NULL},
344     {"export-use-hints", 't',
345      POPT_ARG_NONE, &sp_export_use_hints, SP_ARG_EXPORT_USE_HINTS,
346      N_("Use stored filename and DPI hints when exporting (only with export-id)"),
347      NULL},
349     {"export-background", 'b',
350      POPT_ARG_STRING, &sp_export_background, SP_ARG_EXPORT_BACKGROUND,
351      N_("Background color of exported bitmap (any SVG-supported color string)"),
352      N_("COLOR")},
354     {"export-background-opacity", 'y',
355      POPT_ARG_STRING, &sp_export_background_opacity, SP_ARG_EXPORT_BACKGROUND_OPACITY,
356      N_("Background opacity of exported bitmap (either 0.0 to 1.0, or 1 to 255)"),
357      N_("VALUE")},
359     {"export-plain-svg", 'l',
360      POPT_ARG_STRING, &sp_export_svg, SP_ARG_EXPORT_SVG,
361      N_("Export document to plain SVG file (no sodipodi or inkscape namespaces)"),
362      N_("FILENAME")},
364     {"export-ps", 'P',
365      POPT_ARG_STRING, &sp_export_ps, SP_ARG_EXPORT_PS,
366      N_("Export document to a PS file"),
367      N_("FILENAME")},
369     {"export-eps", 'E',
370      POPT_ARG_STRING, &sp_export_eps, SP_ARG_EXPORT_EPS,
371      N_("Export document to an EPS file"),
372      N_("FILENAME")},
374     {"export-pdf", 'A',
375      POPT_ARG_STRING, &sp_export_pdf, SP_ARG_EXPORT_PDF,
376      N_("Export document to a PDF file"),
377      N_("FILENAME")},
379     {"export-latex", 0,
380      POPT_ARG_NONE, &sp_export_latex, SP_ARG_EXPORT_LATEX,
381      N_("Export PDF/PS/EPS without text. Besides the PDF/PS/EPS, a LaTeX file is exported, putting the text on top of the PDF/PS/EPS file. Include the result in LaTeX like: \\input{latexfile.tex}"),
382      NULL},
384 #ifdef WIN32
385     {"export-emf", 'M',
386      POPT_ARG_STRING, &sp_export_emf, SP_ARG_EXPORT_EMF,
387      N_("Export document to an Enhanced Metafile (EMF) File"),
388      N_("FILENAME")},
389 #endif //WIN32
391     {"export-text-to-path", 'T',
392      POPT_ARG_NONE, &sp_export_text_to_path, SP_ARG_EXPORT_TEXT_TO_PATH,
393      N_("Convert text object to paths on export (PS, EPS, PDF)"),
394      NULL},
396     {"export-ignore-filters", 0,
397      POPT_ARG_NONE, &sp_export_ignore_filters, SP_ARG_EXPORT_IGNORE_FILTERS,
398      N_("Render filtered objects without filters, instead of rasterizing (PS, EPS, PDF)"),
399      NULL},
401     {"query-x", 'X',
402      POPT_ARG_NONE, &sp_query_x, SP_ARG_QUERY_X,
403      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
404      N_("Query the X coordinate of the drawing or, if specified, of the object with --query-id"),
405      NULL},
407     {"query-y", 'Y',
408      POPT_ARG_NONE, &sp_query_y, SP_ARG_QUERY_Y,
409      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
410      N_("Query the Y coordinate of the drawing or, if specified, of the object with --query-id"),
411      NULL},
413     {"query-width", 'W',
414      POPT_ARG_NONE, &sp_query_width, SP_ARG_QUERY_WIDTH,
415      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
416      N_("Query the width of the drawing or, if specified, of the object with --query-id"),
417      NULL},
419     {"query-height", 'H',
420      POPT_ARG_NONE, &sp_query_height, SP_ARG_QUERY_HEIGHT,
421      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
422      N_("Query the height of the drawing or, if specified, of the object with --query-id"),
423      NULL},
425     {"query-all", 'S',
426      POPT_ARG_NONE, &sp_query_all, SP_ARG_QUERY_ALL,
427      N_("List id,x,y,w,h for all objects"),
428      NULL},
430     {"query-id", 'I',
431      POPT_ARG_STRING, &sp_query_id, SP_ARG_QUERY_ID,
432      N_("The ID of the object whose dimensions are queried"),
433      N_("ID")},
435     {"extension-directory", 'x',
436      POPT_ARG_NONE, NULL, SP_ARG_EXTENSIONDIR,
437      // TRANSLATORS: this option makes Inkscape print the name (path) of the extension directory
438      N_("Print out the extension directory and exit"),
439      NULL},
441     {"vacuum-defs", 0,
442      POPT_ARG_NONE, &sp_vacuum_defs, SP_ARG_VACUUM_DEFS,
443      N_("Remove unused definitions from the defs section(s) of the document"),
444      NULL},
446     {"verb-list", 0,
447      POPT_ARG_NONE, NULL, SP_ARG_VERB_LIST,
448      N_("List the IDs of all the verbs in Inkscape"),
449      NULL},
451     {"verb", 0,
452      POPT_ARG_STRING, NULL, SP_ARG_VERB,
453      N_("Verb to call when Inkscape opens."),
454      N_("VERB-ID")},
456     {"select", 0,
457      POPT_ARG_STRING, NULL, SP_ARG_SELECT,
458      N_("Object ID to select when Inkscape opens."),
459      N_("OBJECT-ID")},
461     {"shell", 0,
462      POPT_ARG_NONE, &sp_shell, SP_ARG_SHELL,
463      N_("Start Inkscape in interactive shell mode."),
464      NULL},
466     POPT_AUTOHELP POPT_TABLEEND
467 };
469 static bool needToRecodeParams = true;
470 gchar * blankParam = g_strdup("");
474 #ifdef WIN32
476 /**
477  * Set up the PATH and PYTHONPATH environment variables on Windows
478  * @param exe Inkscape executable directory in UTF-8
479  */
480 static void _win32_set_inkscape_env(gchar const *exe)
482     gchar const *path = g_getenv("PATH");
483     gchar const *pythonpath = g_getenv("PYTHONPATH");
485     gchar *python = g_build_filename(exe, "python", NULL);
486     gchar *scripts = g_build_filename(exe, "python", "Scripts", NULL);
487     gchar *perl = g_build_filename(exe, "python", NULL);
488     gchar *pythonlib = g_build_filename(exe, "python", "Lib", NULL);
489     gchar *pythondll = g_build_filename(exe, "python", "DLLs", NULL);
490     
491     // Python 2.x needs short paths in PYTHONPATH.
492     // Otherwise it doesn't work when Inkscape is installed in Unicode directories.
493     // g_win32_locale_filename_from_utf8 is the GLib wrapper for GetShortPathName.
494     // Remove this once we move to Python 3.0.
495     gchar *python_s = g_win32_locale_filename_from_utf8(python);
496     gchar *pythonlib_s = g_win32_locale_filename_from_utf8(pythonlib);
497     gchar *pythondll_s = g_win32_locale_filename_from_utf8(pythondll);
499     gchar *new_path;
500     gchar *new_pythonpath;
501     if (path) {
502         new_path = g_strdup_printf("%s;%s;%s;%s;%s", exe, python, scripts, perl, path);
503     } else {
504         new_path = g_strdup_printf("%s;%s;%s;%s", exe, python, scripts, perl);
505     }
506     if (pythonpath) {
507         new_pythonpath = g_strdup_printf("%s;%s;%s;%s",
508              python_s, pythonlib_s, pythondll_s, pythonpath);
509     } else {
510         new_pythonpath = g_strdup_printf("%s;%s;%s",
511             python_s, pythonlib_s, pythondll_s);
512     }
514     g_setenv("PATH", new_path, TRUE);
515     g_setenv("PYTHONPATH", new_pythonpath, TRUE);
517     /*
518     printf("PATH = %s\n\n", g_getenv("PATH"));
519     printf("PYTHONPATH = %s\n\n", g_getenv("PYTHONPATH"));
521     gchar *p = g_find_program_in_path("python");
522     if (p) {
523         printf("python in %s\n\n", p);
524         g_free(p);
525     } else {
526         printf("python not found\n\n");
527     }*/
529     g_free(python);
530     g_free(scripts);
531     g_free(perl);
532     g_free(pythonlib);
533     g_free(pythondll);
534     
535     g_free(python_s);
536     g_free(pythonlib_s);
537     g_free(pythondll_s);
539     g_free(new_path);
540     g_free(new_pythonpath);
542 #endif
544 static void set_extensions_env()
546     gchar const *pythonpath = g_getenv("PYTHONPATH");
547     gchar *extdir;
548     
549 #ifdef WIN32
550     extdir = g_win32_locale_filename_from_utf8(INKSCAPE_EXTENSIONDIR);
551 #else
552     extdir = g_strdup(INKSCAPE_EXTENSIONDIR);
553 #endif
555     gchar *new_pythonpath = g_strdup_printf("%s" G_SEARCHPATH_SEPARATOR_S "%s",
556                                             extdir, pythonpath);
557     g_setenv("PYTHONPATH", new_pythonpath, TRUE);
558     g_free(extdir);
559     g_free(new_pythonpath);
562 /**
563  * This is the classic main() entry point of the program, though on some
564  * architectures it might be called by something else.
565  */
566 int
567 main(int argc, char **argv)
569 #ifdef HAVE_FPSETMASK
570     /* This is inherited from Sodipodi code, where it was in #ifdef __FreeBSD__.  It's probably
571        safe to remove: the default mask is already 0 in C99, and in current FreeBSD according to
572        the fenv man page on www.freebsd.org, and in glibc according to (libc)FP Exceptions. */
573     fpsetmask(fpgetmask() & ~(FP_X_DZ | FP_X_INV));
574 #endif
576 #ifdef WIN32
577     /*
578       Set the current directory to the directory of the
579       executable.  This seems redundant, but is needed for
580       when inkscape.exe is executed from another directory.
581       We use relative paths on win32.
582       HKCR\svgfile\shell\open\command is a good example
584       TODO: this breaks the CLI on Windows, see LP #167455
585       However, the CLI is broken anyway, because we are a GUI app
586     */
587     const int pathbuf = 2048;
588     gunichar2 *path = g_new(gunichar2, pathbuf);
589     GetModuleFileNameW(NULL, (WCHAR*) path, pathbuf);
590     gchar *inkscape = g_utf16_to_utf8(path, -1, NULL, NULL, NULL);
591     gchar *exedir = g_path_get_dirname(inkscape);
592     gunichar2 *dirw = g_utf8_to_utf16(exedir, -1, NULL, NULL, NULL);
593     SetCurrentDirectoryW((WCHAR*) dirw);
594     _win32_set_inkscape_env(exedir);
596 # ifdef ENABLE_NLS
597     // obtain short path to executable dir and pass it
598     // to bindtextdomain (it doesn't understand UTF-8)
599     gchar *shortexedir = g_win32_locale_filename_from_utf8(exedir);
600     gchar *localepath = g_build_filename(shortexedir, PACKAGE_LOCALE_DIR, NULL);
601     bindtextdomain(GETTEXT_PACKAGE, localepath);
602     g_free(shortexedir);
603     g_free(localepath);
604 # endif
605     
606     g_free(path);
607     g_free(inkscape);
608     g_free(exedir);
609     g_free(dirw);
611     // Don't touch the registry (works fine without it) for Inkscape Portable
612     gchar const *val = g_getenv("INKSCAPE_PORTABLE_PROFILE_DIR");
613     if (!val) {
614         RegistryTool rt;
615         rt.setPathInfo();
616     }
617 #elif defined(ENABLE_NLS)
618 # ifdef ENABLE_BINRELOC
619     bindtextdomain(GETTEXT_PACKAGE, BR_LOCALEDIR(""));
620 # else
621     bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
622 # endif
623 #endif
625     // the bit below compiles regardless of platform
626 #ifdef ENABLE_NLS
627     // Allow the user to override the locale directory by setting
628     // the environment variable INKSCAPE_LOCALEDIR.
629     char const *inkscape_localedir = g_getenv("INKSCAPE_LOCALEDIR");
630     if (inkscape_localedir != NULL) {
631         bindtextdomain(GETTEXT_PACKAGE, inkscape_localedir);
632     }
634     // common setup
635     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
636     textdomain(GETTEXT_PACKAGE);
637 #endif
639     set_extensions_env();
641     // Prevents errors like "Unable to wrap GdkPixbuf..." (in nr-filter-image.cpp for example)
642     Gtk::Main::init_gtkmm_internals();
644     LIBXML_TEST_VERSION
646     Inkscape::GC::init();
648     Inkscape::Debug::Logger::init();
650     gboolean use_gui;
652 #ifndef WIN32
653     use_gui = (g_getenv("DISPLAY") != NULL);
654 #else
655     use_gui = TRUE;
656 #endif
657     /* Test whether with/without GUI is forced */
658     for (int i = 1; i < argc; i++) {
659         if (!strcmp(argv[i], "-z")
660             || !strcmp(argv[i], "--without-gui")
661             || !strcmp(argv[i], "-p")
662             || !strncmp(argv[i], "--print", 7)
663             || !strcmp(argv[i], "-e")
664             || !strncmp(argv[i], "--export-png", 12)
665             || !strcmp(argv[i], "-l")
666             || !strncmp(argv[i], "--export-plain-svg", 18)
667             || !strcmp(argv[i], "-i")
668             || !strncmp(argv[i], "--export-area-drawing", 21)
669             || !strcmp(argv[i], "-D")
670             || !strncmp(argv[i], "--export-area-page", 18)
671             || !strcmp(argv[i], "-C")
672             || !strncmp(argv[i], "--export-id", 11)
673             || !strcmp(argv[i], "-P")
674             || !strncmp(argv[i], "--export-ps", 11)
675             || !strcmp(argv[i], "-E")
676             || !strncmp(argv[i], "--export-eps", 12)
677             || !strcmp(argv[i], "-A")
678             || !strncmp(argv[i], "--export-pdf", 12)
679             || !strncmp(argv[i], "--export-latex", 14)
680 #ifdef WIN32
681             || !strcmp(argv[i], "-M")
682             || !strncmp(argv[i], "--export-emf", 12)
683 #endif //WIN32
684             || !strcmp(argv[i], "-W")
685             || !strncmp(argv[i], "--query-width", 13)
686             || !strcmp(argv[i], "-H")
687             || !strncmp(argv[i], "--query-height", 14)
688             || !strcmp(argv[i], "-S")
689             || !strncmp(argv[i], "--query-all", 11)
690             || !strcmp(argv[i], "-X")
691             || !strncmp(argv[i], "--query-x", 9)
692             || !strcmp(argv[i], "-Y")
693             || !strncmp(argv[i], "--query-y", 9)
694             || !strcmp(argv[i], "--vacuum-defs")
695             || !strcmp(argv[i], "--shell")
696            )
697         {
698             /* main_console handles any exports -- not the gui */
699             use_gui = FALSE;
700             break;
701         } else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "--with-gui")) {
702             use_gui = TRUE;
703             break;
704         }
705     }
707 #ifdef WIN32
708 #ifndef REPLACEARGS_ANSI
709     if ( PrintWin32::is_os_wide() )
710 #endif // REPLACEARGS_ANSI
711     {
712         // If the call fails, we'll need to convert charsets
713         needToRecodeParams = !replaceArgs( argc, argv );
714     }
715 #endif // WIN32
717     /// \todo  Should this be a static object (see inkscape.cpp)?
718     Inkscape::NSApplication::Application app(argc, argv, use_gui, sp_new_gui);
720     return app.run();
726 void fixupSingleFilename( gchar **orig, gchar **spare )
728     if ( orig && *orig && **orig ) {
729         GError *error = NULL;
730         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(*orig, -1, NULL, NULL, &error);
731         if ( newFileName )
732         {
733             *orig = newFileName;
734             if ( spare ) {
735                 *spare = newFileName;
736             }
737 //             g_message("Set a replacement fixup");
738         }
739     }
744 GSList *fixupFilenameEncoding( GSList* fl )
746     GSList *newFl = NULL;
747     while ( fl ) {
748         gchar *fn = static_cast<gchar*>(fl->data);
749         fl = g_slist_remove( fl, fl->data );
750         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(fn, -1, NULL, NULL, NULL);
751         if ( newFileName ) {
753             if ( 0 )
754             {
755                 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
756                 gchar *safeNewFn = Inkscape::IO::sanitizeString(newFileName);
757                 GtkWidget *w = gtk_message_dialog_new( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
758                                                        "Note: Converted '%s' to '%s'", safeFn, safeNewFn );
759                 gtk_dialog_run (GTK_DIALOG (w));
760                 gtk_widget_destroy (w);
761                 g_free(safeNewFn);
762                 g_free(safeFn);
763             }
765             g_free( fn );
766             fn = newFileName;
767             newFileName = 0;
768         }
769         else
770             if ( 0 )
771         {
772             gchar *safeFn = Inkscape::IO::sanitizeString(fn);
773             GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "Error: Unable to convert '%s'", safeFn );
774             gtk_dialog_run (GTK_DIALOG (w));
775             gtk_widget_destroy (w);
776             g_free(safeFn);
777         }
778         newFl = g_slist_append( newFl, fn );
779     }
780     return newFl;
783 int sp_common_main( int argc, char const **argv, GSList **flDest )
785     /// \todo fixme: Move these to some centralized location (Lauris)
786     sp_object_type_register("sodipodi:namedview", SP_TYPE_NAMEDVIEW);
787     sp_object_type_register("sodipodi:guide", SP_TYPE_GUIDE);
790     // temporarily switch gettext encoding to locale, so that help messages can be output properly
791     gchar const *charset;
792     g_get_charset(&charset);
794     bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
796     poptContext ctx = poptGetContext(NULL, argc, argv, options, 0);
797     poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
798     g_return_val_if_fail(ctx != NULL, 1);
800     /* Collect own arguments */
801     GSList *fl = sp_process_args(ctx);
802     poptFreeContext(ctx);
804     // now switch gettext back to UTF-8 (for GUI)
805     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
807     // Now let's see if the file list still holds up
808     if ( needToRecodeParams )
809     {
810         fl = fixupFilenameEncoding( fl );
811     }
813     // Check the globals for filename-fixup
814     if ( needToRecodeParams )
815     {
816         fixupSingleFilename( &sp_export_png, &sp_export_png_utf8 );
817         fixupSingleFilename( &sp_export_svg, &sp_export_svg_utf8 );
818         fixupSingleFilename( &sp_global_printer, &sp_global_printer_utf8 );
819     }
820     else
821     {
822         if ( sp_export_png )
823             sp_export_png_utf8 = g_strdup( sp_export_png );
824         if ( sp_export_svg )
825             sp_export_svg_utf8 = g_strdup( sp_export_svg );
826         if ( sp_global_printer )
827             sp_global_printer_utf8 = g_strdup( sp_global_printer );
828     }
830     // Return the list if wanted, else free it up.
831     if ( flDest ) {
832         *flDest = fl;
833         fl = 0;
834     } else {
835         while ( fl ) {
836             g_free( fl->data );
837             fl = g_slist_remove( fl, fl->data );
838         }
839     }
840     return 0;
843 static void
844 snooper(GdkEvent *event, gpointer /*data*/) {
845     if (inkscape_mapalt())  /* returns the map of the keyboard modifier to map to Alt, zero if no mapping */
846     {
847         GdkModifierType mapping=(GdkModifierType)inkscape_mapalt();
848         switch (event->type) {
849             case GDK_MOTION_NOTIFY:
850                 if(event->motion.state & mapping) {
851                     event->motion.state|=GDK_MOD1_MASK;
852                 }
853                 break;
854             case GDK_BUTTON_PRESS:
855                 if(event->button.state & mapping) {
856                     event->button.state|=GDK_MOD1_MASK;
857                 }
858                 break;
859              case GDK_KEY_PRESS:
860                  if(event->key.state & mapping) {
861                      event->key.state|=GDK_MOD1_MASK;
862                  }
863                  break;
864         default:
865             break;
866         }
867     }
869     if (inkscape_trackalt()) {
870         // MacOS X with X11 has some problem with the default
871         // xmodmapping.  A ~/.xmodmap solution does not work reliably due
872         // to the way we package our executable in a .app that can launch
873         // X11 or use an already-running X11.  The same problem has been
874         // reported on Linux but there is no .app/X11 to get in the way
875         // of ~/.xmodmap fixes.  So we make this a preference.
876         //
877         // For some reason, Gdk senses changes in Alt (Mod1) state for
878         // many message types, but not for keystrokes!  So this ugly hack
879         // tracks what the state of Alt-pressing is, and ensures
880         // GDK_MOD1_MASK is in the event->key.state as appropriate.
881         //
882         static gboolean altL_pressed = FALSE;
883         static gboolean altR_pressed = FALSE;
884         static gboolean alt_pressed = FALSE;
885         guint get_group0_keyval(GdkEventKey* event);
886         guint keyval = 0;
887         switch (event->type) {
888         case GDK_MOTION_NOTIFY:
889             alt_pressed = TRUE && (event->motion.state & GDK_MOD1_MASK);
890             break;
891         case GDK_BUTTON_PRESS:
892             alt_pressed = TRUE && (event->button.state & GDK_MOD1_MASK);
893             break;
894         case GDK_KEY_PRESS:
895             keyval = get_group0_keyval(&event->key);
896             if (keyval == GDK_Alt_L) altL_pressed = TRUE;
897             if (keyval == GDK_Alt_R) altR_pressed = TRUE;
898             alt_pressed = alt_pressed || altL_pressed || altR_pressed;
899             alt_pressed = alt_pressed || (event->button.state & GDK_MOD1_MASK);
900             if (alt_pressed)
901                 event->key.state |= GDK_MOD1_MASK;
902             else
903                 event->key.state &= ~GDK_MOD1_MASK;
904             break;
905         case GDK_KEY_RELEASE:
906             keyval = get_group0_keyval(&event->key);
907             if (keyval == GDK_Alt_L) altL_pressed = FALSE;
908             if (keyval == GDK_Alt_R) altR_pressed = FALSE;
909             if (!altL_pressed && !altR_pressed)
910                 alt_pressed = FALSE;
911             break;
912         default:
913             break;
914         }
915         //printf("alt_pressed: %s\n", alt_pressed? "+" : "-");
916     }
918     gtk_main_do_event (event);
921 static std::vector<Glib::ustring> getDirectorySet(const gchar* userDir, const gchar* const * systemDirs) {
922     std::vector<Glib::ustring> listing;
923     listing.push_back(userDir);
924     for ( const char* const* cur = systemDirs; *cur; cur++ )
925     {
926         listing.push_back(*cur);
927     }
928     return listing;
931 int
932 sp_main_gui(int argc, char const **argv)
934     Gtk::Main main_instance (&argc, const_cast<char ***>(&argv));
936     GSList *fl = NULL;
937     int retVal = sp_common_main( argc, argv, &fl );
938     g_return_val_if_fail(retVal == 0, 1);
940     // Add possible icon entry directories
941     std::vector<Glib::ustring> dataDirs = getDirectorySet( g_get_user_data_dir(),
942                                                            g_get_system_data_dirs() );
943     for (std::vector<Glib::ustring>::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it)
944     {
945         std::vector<Glib::ustring> listing;
946         listing.push_back(*it);
947         listing.push_back("inkscape");
948         listing.push_back("icons");
949         Glib::ustring dir = Glib::build_filename(listing);
950         gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), dir.c_str());
951     }
953     // Add our icon directory to the search path for icon theme lookups.
954     gchar *usericondir = profile_path("icons");
955     gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), usericondir);
956     gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), INKSCAPE_PIXMAPDIR);
957     g_free(usericondir);
959     gdk_event_handler_set((GdkEventFunc)snooper, NULL, NULL);
960     Inkscape::Debug::log_display_config();
962     // Set default window icon. Obeys the theme.
963     gtk_window_set_default_icon_name("inkscape");
964     // Do things that were previously in inkscape_gtk_stock_init().
965     sp_icon_get_phys_size(GTK_ICON_SIZE_MENU);
966     Inkscape::UI::Widget::Panel::prep();
968     gboolean create_new = TRUE;
970     /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
971     inkscape_application_init(argv[0], true);
973     while (fl) {
974         if (sp_file_open((gchar *)fl->data,NULL)) {
975             create_new=FALSE;
976         }
977         fl = g_slist_remove(fl, fl->data);
978     }
979     if (create_new) {
980         sp_file_new_default();
981     }
983     Glib::signal_idle().connect(sigc::ptr_fun(&Inkscape::CmdLineAction::idle));
984     main_instance.run();
986 #ifdef WIN32
987     //We might not need anything here
988     //sp_win32_finish(); <-- this is a NOP func
989 #endif
991     return 0;
994 /**
995  * Process file list
996  */
997 void sp_process_file_list(GSList *fl)
999     while (fl) {
1000         const gchar *filename = (gchar *)fl->data;
1002         SPDocument *doc = NULL;
1003         try {
1004             doc = Inkscape::Extension::open(NULL, filename);
1005         } catch (Inkscape::Extension::Input::no_extension_found &e) {
1006             doc = NULL;
1007         } catch (Inkscape::Extension::Input::open_failed &e) {
1008             doc = NULL;
1009         }
1011         if (doc == NULL) {
1012             try {
1013                 doc = Inkscape::Extension::open(Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), filename);
1014             } catch (Inkscape::Extension::Input::no_extension_found &e) {
1015                 doc = NULL;
1016             } catch (Inkscape::Extension::Input::open_failed &e) {
1017                 doc = NULL;
1018             }
1019         }
1020         if (doc == NULL) {
1021             g_warning("Specified document %s cannot be opened (does not exist or not a valid SVG file)", filename);
1022         } else {
1023             if (sp_vacuum_defs) {
1024                 vacuum_document(doc);
1025             }
1026             if (sp_vacuum_defs && !sp_export_svg) {
1027                 // save under the name given in the command line
1028                 sp_repr_save_file(doc->rdoc, filename, SP_SVG_NS_URI);
1029             }
1030             if (sp_global_printer) {
1031                 sp_print_document_to_file(doc, sp_global_printer);
1032             }
1033             if (sp_export_png || (sp_export_id && sp_export_use_hints)) {
1034                 sp_do_export_png(doc);
1035             }
1036             if (sp_export_svg) {
1037                 Inkscape::XML::Document *rdoc;
1038                 Inkscape::XML::Node *repr;
1039                 rdoc = sp_repr_document_new("svg:svg");
1040                 repr = rdoc->root();
1041                 repr = sp_document_root(doc)->updateRepr(rdoc, repr, SP_OBJECT_WRITE_BUILD);
1042                 sp_repr_save_rebased_file(repr->document(), sp_export_svg, SP_SVG_NS_URI,
1043                                           doc->base, sp_export_svg);
1044             }
1045             if (sp_export_ps) {
1046                 do_export_ps_pdf(doc, sp_export_ps, "image/x-postscript");
1047             }
1048             if (sp_export_eps) {
1049                 do_export_ps_pdf(doc, sp_export_eps, "image/x-e-postscript");
1050             }
1051             if (sp_export_pdf) {
1052                 do_export_ps_pdf(doc, sp_export_pdf, "application/pdf");
1053             }
1054 #ifdef WIN32
1055             if (sp_export_emf) {
1056                 do_export_emf(doc, sp_export_emf, "image/x-emf");
1057             }
1058 #endif //WIN32
1059             if (sp_query_all) {
1060                 do_query_all (doc);
1061             } else if (sp_query_width || sp_query_height) {
1062                 do_query_dimension (doc, true, sp_query_width? Geom::X : Geom::Y, sp_query_id);
1063             } else if (sp_query_x || sp_query_y) {
1064                 do_query_dimension (doc, false, sp_query_x? Geom::X : Geom::Y, sp_query_id);
1065             }
1067             delete doc;
1068         }
1069         fl = g_slist_remove(fl, fl->data);
1070     }
1073 /**
1074  * Run the application as an interactive shell, parsing command lines from stdin
1075  * Returns -1 on error.
1076  */
1077 int sp_main_shell(char const* command_name)
1079     int retval = 0;
1081     const unsigned int buffer_size = 4096;
1082     gchar *command_line = g_strnfill(buffer_size, 0);
1083     g_strlcpy(command_line, command_name, buffer_size);
1084     gsize offset = g_strlcat(command_line, " ", buffer_size);
1085     gsize sizeLeft = buffer_size - offset;
1086     gchar *useme = command_line + offset;
1088     fprintf(stdout, "Inkscape %s interactive shell mode. Type 'quit' to quit.\n", Inkscape::version_string);
1089     fflush(stdout);
1090     char* linedata = 0;
1091     do {
1092         fprintf(stdout, ">");
1093         fflush(stdout);
1094         if ((linedata = fgets(useme, sizeLeft, stdin))) {
1095             size_t len = strlen(useme);
1096             if ( (len >= sizeLeft - 1) || (useme[len - 1] != '\n') ) {
1097                 fprintf(stdout, "ERROR: Command line too long\n");
1098                 // Consume rest of line
1099                 retval = -1; // If the while loop completes, this remains -1
1100                 while (fgets(useme, sizeLeft, stdin) && retval) {
1101                     len = strlen(command_line);
1102                     if ( (len < buffer_size) && (command_line[len-1] == '\n') ) {
1103                         retval = 0;
1104                     }
1105                 }
1106             } else {
1107                 useme[--len] = '\0';  // Strip newline
1108                 if (useme[len - 1] == '\r') {
1109                     useme[--len] = '\0';
1110                 }
1111                 if ( strcmp(useme, "quit") == 0 ) {
1112                     // Time to quit
1113                     fflush(stdout);
1114                     linedata = 0; // mark for exit
1115                 } else if ( len < 1 ) {
1116                     // blank string. Do nothing.
1117                 } else {
1118                     GError* parseError = 0;
1119                     gchar** argv = 0;
1120                     gint argc = 0;
1121                     if ( g_shell_parse_argv(command_line, &argc, &argv, &parseError) ) {
1122                         poptContext ctx = poptGetContext(NULL, argc, const_cast<const gchar**>(argv), options, 0);
1123                         poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
1124                         if ( ctx ) {
1125                             GSList *fl = sp_process_args(ctx);
1126                             sp_process_file_list(fl);
1127                             poptFreeContext(ctx);
1128                         } else {
1129                             retval = 1; // not sure why. But this was the previous return value
1130                         }
1131                         resetCommandlineGlobals();
1132                         g_strfreev(argv);
1133                     } else {
1134                         g_warning("Cannot parse commandline: %s", useme);
1135                     }
1136                 }
1137             }
1138         } // if (linedata...
1139     } while (linedata && (retval == 0));
1141     g_free(command_line);
1142     return retval;
1145 int sp_main_console(int argc, char const **argv)
1147     /* We are started in text mode */
1149     /* Do this g_type_init(), so that we can use Xft/Freetype2 (Pango)
1150      * in a non-Gtk environment.  Used in libnrtype's
1151      * FontInstance.cpp and FontFactory.cpp.
1152      * http://mail.gnome.org/archives/gtk-list/2003-December/msg00063.html
1153      */
1154     g_type_init();
1155     char **argv2 = const_cast<char **>(argv);
1156     gtk_init_check( &argc, &argv2 );
1157     //setlocale(LC_ALL, "");
1159     GSList *fl = NULL;
1160     int retVal = sp_common_main( argc, argv, &fl );
1161     g_return_val_if_fail(retVal == 0, 1);
1163     if (fl == NULL && !sp_shell) {
1164         g_print("Nothing to do!\n");
1165         exit(0);
1166     }
1168     inkscape_application_init(argv[0], false);
1170     if (sp_shell) {
1171         sp_main_shell(argv[0]); // Run as interactive shell
1172         exit(0);
1173     } else {
1174         sp_process_file_list(fl); // Normal command line invokation
1175     }
1177     return 0;
1180 static void
1181 do_query_dimension (SPDocument *doc, bool extent, Geom::Dim2 const axis, const gchar *id)
1183     SPObject *o = NULL;
1185     if (id) {
1186         o = doc->getObjectById(id);
1187         if (o) {
1188             if (!SP_IS_ITEM (o)) {
1189                 g_warning("Object with id=\"%s\" is not a visible item. Cannot query dimensions.", id);
1190                 return;
1191             }
1192         } else {
1193             g_warning("Object with id=\"%s\" is not found. Cannot query dimensions.", id);
1194             return;
1195         }
1196     } else {
1197         o = SP_DOCUMENT_ROOT(doc);
1198     }
1200     if (o) {
1201         sp_document_ensure_up_to_date (doc);
1202         SPItem *item = ((SPItem *) o);
1204         // "true" SVG bbox for scripting
1205         Geom::OptRect area = item->getBounds(sp_item_i2doc_affine(item));
1206         if (area) {
1207             Inkscape::SVGOStringStream os;
1208             if (extent) {
1209                 os << area->dimensions()[axis];
1210             } else {
1211                 os << area->min()[axis];
1212             }
1213             g_print ("%s", os.str().c_str());
1214         } else {
1215             g_print("0");
1216         }
1217     }
1220 static void
1221 do_query_all (SPDocument *doc)
1223     SPObject *o = NULL;
1225     o = SP_DOCUMENT_ROOT(doc);
1227     if (o) {
1228         sp_document_ensure_up_to_date (doc);
1229         do_query_all_recurse(o);
1230     }
1233 static void
1234 do_query_all_recurse (SPObject *o)
1236     SPItem *item = ((SPItem *) o);
1237     if (o->getId() && SP_IS_ITEM(item)) {
1238         Geom::OptRect area = item->getBounds(sp_item_i2doc_affine(item));
1239         if (area) {
1240             Inkscape::SVGOStringStream os;
1241             os << o->getId();
1242             os << "," << area->min()[Geom::X];
1243             os << "," << area->min()[Geom::Y];
1244             os << "," << area->dimensions()[Geom::X];
1245             os << "," << area->dimensions()[Geom::Y];
1246             g_print ("%s\n", os.str().c_str());
1247         }
1248     }
1250     SPObject *child = o->children;
1251     while (child) {
1252         do_query_all_recurse (child);
1253         child = child->next;
1254     }
1258 static void
1259 sp_do_export_png(SPDocument *doc)
1261     const gchar *filename = NULL;
1262     bool filename_from_hint = false;
1263     gdouble dpi = 0.0;
1265     if (sp_export_use_hints && (!sp_export_id && !sp_export_area_drawing)) {
1266         g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored.");
1267     }
1269     GSList *items = NULL;
1271     Geom::Rect area;
1272     if (sp_export_id || sp_export_area_drawing) {
1274         SPObject *o = NULL;
1275         SPObject *o_area = NULL;
1276         if (sp_export_id && sp_export_area_drawing) {
1277             o = doc->getObjectById(sp_export_id);
1278             o_area = SP_DOCUMENT_ROOT (doc);
1279         } else if (sp_export_id) {
1280             o = doc->getObjectById(sp_export_id);
1281             o_area = o;
1282         } else if (sp_export_area_drawing) {
1283             o = SP_DOCUMENT_ROOT (doc);
1284             o_area = o;
1285         }
1287         if (o) {
1288             if (!SP_IS_ITEM (o)) {
1289                 g_warning("Object with id=\"%s\" is not a visible item. Nothing exported.", sp_export_id);
1290                 return;
1291             }
1293             items = g_slist_prepend (items, SP_ITEM(o));
1295             if (sp_export_id_only) {
1296                 g_print("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id);
1297             }
1299             if (sp_export_use_hints) {
1301                 // retrieve export filename hint
1302                 const gchar *fn_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-filename");
1303                 if (fn_hint) {
1304                     if (sp_export_png) {
1305                         g_warning ("Using export filename from the command line (--export-png). Filename hint %s is ignored.", fn_hint);
1306                         filename = sp_export_png;
1307                     } else {
1308                         filename = fn_hint;
1309                         filename_from_hint = true;
1310                     }
1311                 } else {
1312                     g_warning ("Export filename hint not found for the object.");
1313                     filename = sp_export_png;
1314                 }
1316                 // retrieve export dpi hints
1317                 const gchar *dpi_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
1318                 if (dpi_hint) {
1319                     if (sp_export_dpi || sp_export_width || sp_export_height) {
1320                         g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint);
1321                     } else {
1322                         dpi = atof(dpi_hint);
1323                     }
1324                 } else {
1325                     g_warning ("Export DPI hint not found for the object.");
1326                 }
1328             }
1330             // write object bbox to area
1331             sp_document_ensure_up_to_date (doc);
1332             Geom::OptRect areaMaybe;
1333             sp_item_invoke_bbox((SPItem *) o_area, areaMaybe, sp_item_i2d_affine((SPItem *) o_area), TRUE);
1334             if (areaMaybe) {
1335                 area = *areaMaybe;
1336             } else {
1337                 g_warning("Unable to determine a valid bounding box. Nothing exported.");
1338                 return;
1339             }
1340         } else {
1341             g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
1342             return;
1343         }
1344     }
1346     if (sp_export_area) {
1347         /* Try to parse area (given in SVG pixels) */
1348         gdouble x0,y0,x1,y1;
1349         if (!sscanf(sp_export_area, "%lg:%lg:%lg:%lg", &x0, &y0, &x1, &y1) == 4) {
1350             g_warning("Cannot parse export area '%s'; use 'x0:y0:x1:y1'. Nothing exported.", sp_export_area);
1351             return;
1352         }
1353         area = Geom::Rect(Geom::Interval(x0,x1), Geom::Interval(y0,y1));
1354     } else if (sp_export_area_page || !(sp_export_id || sp_export_area_drawing)) {
1355         /* Export the whole page: note: Inkscape uses 'page' in all menus and dialogs, not 'canvas' */
1356         sp_document_ensure_up_to_date (doc);
1357         Geom::Point origin (SP_ROOT(doc->root)->x.computed, SP_ROOT(doc->root)->y.computed);
1358         area = Geom::Rect(origin, origin + sp_document_dimensions(doc));
1359     }
1361     // set filename and dpi from options, if not yet set from the hints
1362     if (!filename) {
1363         if (!sp_export_png) {
1364             g_warning ("No export filename given and no filename hint. Nothing exported.");
1365             return;
1366         }
1367         filename = sp_export_png;
1368     }
1370     if (sp_export_dpi && dpi == 0.0) {
1371         dpi = atof(sp_export_dpi);
1372         if ((dpi < 0.1) || (dpi > 10000.0)) {
1373             g_warning("DPI value %s out of range [0.1 - 10000.0]. Nothing exported.", sp_export_dpi);
1374             return;
1375         }
1376         g_print("DPI: %g\n", dpi);
1377     }
1379     if (sp_export_area_snap) {
1380         round_rectangle_outwards(area);
1381     }
1383     // default dpi
1384     if (dpi == 0.0) {
1385         dpi = PX_PER_IN;
1386     }
1388     unsigned long int width = 0;
1389     unsigned long int height = 0;
1391     if (sp_export_width) {
1392         errno=0;
1393         width = strtoul(sp_export_width, NULL, 0);
1394         if ((width < 1) || (width > PNG_UINT_31_MAX) || (errno == ERANGE) ) {
1395             g_warning("Export width %lu out of range (1 - %lu). Nothing exported.", width, (unsigned long int)PNG_UINT_31_MAX);
1396             return;
1397         }
1398         dpi = (gdouble) width * PX_PER_IN / area.width();
1399     }
1401     if (sp_export_height) {
1402         errno=0;
1403         height = strtoul(sp_export_height, NULL, 0);
1404         if ((height < 1) || (height > PNG_UINT_31_MAX)) {
1405             g_warning("Export height %lu out of range (1 - %lu). Nothing exported.", height, (unsigned long int)PNG_UINT_31_MAX);
1406             return;
1407         }
1408         dpi = (gdouble) height * PX_PER_IN / area.height();
1409     }
1411     if (!sp_export_width) {
1412         width = (unsigned long int) (area.width() * dpi / PX_PER_IN + 0.5);
1413     }
1415     if (!sp_export_height) {
1416         height = (unsigned long int) (area.height() * dpi / PX_PER_IN + 0.5);
1417     }
1419     guint32 bgcolor = 0x00000000;
1420     if (sp_export_background) {
1421         // override the page color
1422         bgcolor = sp_svg_read_color(sp_export_background, 0xffffff00);
1423         bgcolor |= 0xff; // default is no opacity
1424     } else {
1425         // read from namedview
1426         Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
1427         if (nv && nv->attribute("pagecolor"))
1428             bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
1429         if (nv && nv->attribute("inkscape:pageopacity"))
1430             bgcolor |= SP_COLOR_F_TO_U(sp_repr_get_double_attribute (nv, "inkscape:pageopacity", 1.0));
1431     }
1433     if (sp_export_background_opacity) {
1434         // override opacity
1435         gfloat value;
1436         if (sp_svg_number_read_f (sp_export_background_opacity, &value)) {
1437             if (value > 1.0) {
1438                 value = CLAMP (value, 1.0f, 255.0f);
1439                 bgcolor &= (guint32) 0xffffff00;
1440                 bgcolor |= (guint32) floor(value);
1441             } else {
1442                 value = CLAMP (value, 0.0f, 1.0f);
1443                 bgcolor &= (guint32) 0xffffff00;
1444                 bgcolor |= SP_COLOR_F_TO_U(value);
1445             }
1446         }
1447     }
1449     gchar *path = 0;
1450     if (filename_from_hint) {
1451         //Make relative paths go from the document location, if possible:
1452         if (!g_path_is_absolute(filename) && doc->uri) {
1453             gchar *dirname = g_path_get_dirname(doc->uri);
1454             if (dirname) {
1455                 path = g_build_filename(dirname, filename, NULL);
1456                 g_free(dirname);
1457             }
1458         }
1459         if (!path) {
1460             path = g_strdup(filename);
1461         }
1462     } else {
1463         path = g_strdup(filename);
1464     }
1466     g_print("Background RRGGBBAA: %08x\n", bgcolor);
1468     g_print("Area %g:%g:%g:%g exported to %lu x %lu pixels (%g dpi)\n", area[Geom::X][0], area[Geom::Y][0], area[Geom::X][1], area[Geom::Y][1], width, height, dpi);
1470     g_print("Bitmap saved as: %s\n", filename);
1472     if ((width >= 1) && (height >= 1) && (width <= PNG_UINT_31_MAX) && (height <= PNG_UINT_31_MAX)) {
1473         sp_export_png_file(doc, path, area, width, height, dpi, dpi, bgcolor, NULL, NULL, true, sp_export_id_only ? items : NULL);
1474     } else {
1475         g_warning("Calculated bitmap dimensions %lu %lu are out of range (1 - %lu). Nothing exported.", width, height, (unsigned long int)PNG_UINT_31_MAX);
1476     }
1478     g_free (path);
1479     g_slist_free (items);
1483 /**
1484  *  Perform a PDF/PS/EPS export
1485  *
1486  *  \param doc Document to export.
1487  *  \param uri URI to export to.
1488  *  \param mime MIME type to export as.
1489  */
1491 static void do_export_ps_pdf(SPDocument* doc, gchar const* uri, char const* mime)
1493     Inkscape::Extension::DB::OutputList o;
1494     Inkscape::Extension::db.get_output_list(o);
1495     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1496     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1497         i++;
1498     }
1500     if (i == o.end())
1501     {
1502         g_warning ("Could not find an extension to export to MIME type %s.", mime);
1503         return;
1504     }
1506     if (sp_export_id) {
1507         SPObject *o = doc->getObjectById(sp_export_id);
1508         if (o == NULL) {
1509             g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
1510             return;
1511         }
1512         (*i)->set_param_string ("exportId", sp_export_id);
1513     } else {
1514         (*i)->set_param_string ("exportId", "");
1515     }
1517     if (sp_export_area_page && sp_export_area_drawing) {
1518         g_warning ("You cannot use --export-area-page and --export-area-drawing at the same time; only the former will take effect.");
1519         sp_export_area_drawing = false;
1520     }
1522     if (sp_export_area_drawing) {
1523         (*i)->set_param_bool ("areaDrawing", TRUE);
1524     } else {
1525         (*i)->set_param_bool ("areaDrawing", FALSE);
1526     }
1528     if (sp_export_area_page) {
1529         if (sp_export_eps) {
1530             g_warning ("EPS cannot have its bounding box extend beyond its content, so if your drawing is smaller than the page, --export-area-page will clip it to drawing.");
1531         }
1532         (*i)->set_param_bool ("areaPage", TRUE);
1533     } else {
1534         (*i)->set_param_bool ("areaPage", FALSE);
1535     }
1537     if (!sp_export_area_drawing && !sp_export_area_page && !sp_export_id) {
1538         // neither is set, set page as default for ps/pdf and drawing for eps
1539         if (sp_export_eps) {
1540             try {
1541                (*i)->set_param_bool("areaDrawing", TRUE);
1542             } catch (...) {}
1543         }
1544     }
1546     if (sp_export_text_to_path) {
1547         (*i)->set_param_bool("textToPath", TRUE);
1548     } else {
1549         (*i)->set_param_bool("textToPath", FALSE);
1550     }
1552     if (sp_export_latex) {
1553         (*i)->set_param_bool("textToLaTeX", TRUE);
1554     } else {
1555         (*i)->set_param_bool("textToLaTeX", FALSE);
1556     }
1558     if (sp_export_ignore_filters) {
1559         (*i)->set_param_bool("blurToBitmap", FALSE);
1560     } else {
1561         (*i)->set_param_bool("blurToBitmap", TRUE);
1563         gdouble dpi = 90.0;
1564         if (sp_export_dpi) {
1565             dpi = atof(sp_export_dpi);
1566             if ((dpi < 1) || (dpi > 10000.0)) {
1567                 g_warning("DPI value %s out of range [1 - 10000]. Using 90 dpi instead.", sp_export_dpi);
1568                 dpi = 90;
1569             }
1570         }
1572         (*i)->set_param_int("resolution", (int) dpi);
1573     }
1575     (*i)->save(doc, uri);
1578 #ifdef WIN32
1579 /**
1580  *  Export a document to EMF
1581  *
1582  *  \param doc Document to export.
1583  *  \param uri URI to export to.
1584  *  \param mime MIME type to export as (should be "image/x-emf")
1585  */
1587 static void do_export_emf(SPDocument* doc, gchar const* uri, char const* mime)
1589     Inkscape::Extension::DB::OutputList o;
1590     Inkscape::Extension::db.get_output_list(o);
1591     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1592     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1593         i++;
1594     }
1596     if (i == o.end())
1597     {
1598         g_warning ("Could not find an extension to export to MIME type %s.", mime);
1599         return;
1600     }
1602     (*i)->save(doc, uri);
1604 #endif //WIN32
1606 #ifdef WIN32
1607 bool replaceArgs( int& argc, char**& argv )
1609     bool worked = false;
1611 #ifdef REPLACEARGS_DEBUG
1612     MessageBoxA( NULL, "GetCommandLineW() getting called", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1613 #endif // REPLACEARGS_DEBUG
1615     wchar_t* line = GetCommandLineW();
1616     if ( line )
1617     {
1618 #ifdef REPLACEARGS_DEBUG
1619         {
1620             gchar* utf8Line = g_utf16_to_utf8( (gunichar2*)line, -1, NULL, NULL, NULL );
1621             if ( utf8Line )
1622             {
1623                 gchar *safe = Inkscape::IO::sanitizeString(utf8Line);
1624                 {
1625                     char tmp[strlen(safe) + 32];
1626                     snprintf( tmp, sizeof(tmp), "GetCommandLineW() = '%s'", safe );
1627                     MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1628                 }
1629             }
1630         }
1631 #endif // REPLACEARGS_DEBUG
1633         int numArgs = 0;
1634         wchar_t** parsed = CommandLineToArgvW( line, &numArgs );
1636 #ifdef REPLACEARGS_ANSI
1637 // test code for trying things on Win95/98/ME
1638         if ( !parsed )
1639         {
1640 #ifdef REPLACEARGS_DEBUG
1641             MessageBoxA( NULL, "Unable to process command-line. Faking it", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1642 #endif // REPLACEARGS_DEBUG
1643             int lineLen = wcslen(line) + 1;
1644             wchar_t* lineDup = new wchar_t[lineLen];
1645             wcsncpy( lineDup, line, lineLen );
1647             int pos = 0;
1648             bool inQuotes = false;
1649             bool inWhitespace = true;
1650             std::vector<int> places;
1651             while ( lineDup[pos] )
1652             {
1653                 if ( inQuotes )
1654                 {
1655                     if ( lineDup[pos] == L'"' )
1656                     {
1657                         inQuotes = false;
1658                     }
1659                 }
1660                 else if ( lineDup[pos] == L'"' )
1661                 {
1662                     inQuotes = true;
1663                     inWhitespace = false;
1664                     places.push_back(pos);
1665                 }
1666                 else if ( lineDup[pos] == L' ' || lineDup[pos] == L'\t' )
1667                 {
1668                     if ( !inWhitespace )
1669                     {
1670                         inWhitespace = true;
1671                         lineDup[pos] = 0;
1672                     }
1673                 }
1674                 else if ( inWhitespace && (lineDup[pos] != L' ' && lineDup[pos] != L'\t') )
1675                 {
1676                     inWhitespace = false;
1677                     places.push_back(pos);
1678                 }
1679                 else
1680                 {
1681                     // consume
1682                 }
1683                 pos++;
1684             }
1685 #ifdef REPLACEARGS_DEBUG
1686             {
1687                 char tmp[256];
1688                 snprintf( tmp, sizeof(tmp), "Counted %d args", places.size() );
1689                 MessageBoxA( NULL, tmp, "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1690             }
1691 #endif // REPLACEARGS_DEBUG
1693             wchar_t** block = new wchar_t*[places.size()];
1694             int i = 0;
1695             for ( std::vector<int>::iterator it = places.begin(); it != places.end(); it++ )
1696             {
1697                 block[i++] = &lineDup[*it];
1698             }
1699             parsed = block;
1700             numArgs = places.size();
1701         }
1702 #endif // REPLACEARGS_ANSI
1704         if ( parsed )
1705         {
1706             std::vector<wchar_t*>expandedArgs;
1707             if ( numArgs > 0 )
1708             {
1709                 expandedArgs.push_back( parsed[0] );
1710             }
1712             for ( int i1 = 1; i1 < numArgs; i1++ )
1713             {
1714                 bool wildcarded = (wcschr(parsed[i1], L'?') != NULL) || (wcschr(parsed[i1], L'*') != NULL);
1715                 wildcarded &= parsed[i1][0] != L'"';
1716                 wildcarded &= parsed[i1][0] != L'-';
1717                 if ( wildcarded )
1718                 {
1719 #ifdef REPLACEARGS_ANSI
1720                     WIN32_FIND_DATAA data;
1721 #else
1722                     WIN32_FIND_DATAW data;
1723 #endif // REPLACEARGS_ANSI
1725                     memset((void *)&data, 0, sizeof(data));
1727                     int baseLen = wcslen(parsed[i1]) + 2;
1728                     wchar_t* base = new wchar_t[baseLen];
1729                     wcsncpy( base, parsed[i1], baseLen );
1730                     wchar_t* last = wcsrchr( base, L'\\' );
1731                     if ( last )
1732                     {
1733                         last[1] = 0;
1734                     }
1735                     else
1736                     {
1737                         base[0] = 0;
1738                     }
1739                     baseLen = wcslen( base );
1741 #ifdef REPLACEARGS_ANSI
1742                     char target[MAX_PATH];
1743                     if ( WideCharToMultiByte( CP_ACP, 0, parsed[i1], -1, target, sizeof(target), NULL, NULL) )
1744                     {
1745                         HANDLE hf = FindFirstFileA( target, &data );
1746 #else
1747                         HANDLE hf = FindFirstFileW( parsed[i1], &data );
1748 #endif // REPLACEARGS_ANSI
1749                         if ( hf != INVALID_HANDLE_VALUE )
1750                         {
1751                             BOOL found = TRUE;
1752                             do
1753                             {
1754 #ifdef REPLACEARGS_ANSI
1755                                 int howMany = MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, NULL, 0 );
1756                                 if ( howMany > 0 )
1757                                 {
1758                                     howMany += baseLen;
1759                                     wchar_t* tmp = new wchar_t[howMany + 1];
1760                                     wcsncpy( tmp, base, howMany + 1 );
1761                                     MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, tmp + baseLen, howMany + 1 - baseLen );
1762                                     expandedArgs.push_back( tmp );
1763                                     found = FindNextFileA( hf, &data );
1764                                 }
1765 #else
1766                                 int howMany = wcslen(data.cFileName) + baseLen;
1767                                 wchar_t* tmp = new wchar_t[howMany + 1];
1768                                 wcsncpy( tmp, base, howMany + 1 );
1769                                 wcsncat( tmp, data.cFileName, howMany + 1 );
1770                                 expandedArgs.push_back( tmp );
1771                                 found = FindNextFileW( hf, &data );
1772 #endif // REPLACEARGS_ANSI
1773                             } while ( found );
1775                             FindClose( hf );
1776                         }
1777                         else
1778                         {
1779                             expandedArgs.push_back( parsed[i1] );
1780                         }
1781 #ifdef REPLACEARGS_ANSI
1782                     }
1783 #endif // REPLACEARGS_ANSI
1785                     delete[] base;
1786                 }
1787                 else
1788                 {
1789                     expandedArgs.push_back( parsed[i1] );
1790                 }
1791             }
1793             {
1794                 wchar_t** block = new wchar_t*[expandedArgs.size()];
1795                 int iz = 0;
1796                 for ( std::vector<wchar_t*>::iterator it = expandedArgs.begin(); it != expandedArgs.end(); it++ )
1797                 {
1798                     block[iz++] = *it;
1799                 }
1800                 parsed = block;
1801                 numArgs = expandedArgs.size();
1802             }
1804             std::vector<gchar*> newArgs;
1805             for ( int i = 0; i < numArgs; i++ )
1806             {
1807                 gchar* replacement = g_utf16_to_utf8( (gunichar2*)parsed[i], -1, NULL, NULL, NULL );
1808                 if ( replacement )
1809                 {
1810 #ifdef REPLACEARGS_DEBUG
1811                     gchar *safe2 = Inkscape::IO::sanitizeString(replacement);
1813                     if ( safe2 )
1814                     {
1815                         {
1816                             char tmp[1024];
1817                             snprintf( tmp, sizeof(tmp), "    [%2d] = '%s'", i, safe2 );
1818                             MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1819                         }
1820                         g_free( safe2 );
1821                     }
1822 #endif // REPLACEARGS_DEBUG
1824                     newArgs.push_back( replacement );
1825                 }
1826                 else
1827                 {
1828                     newArgs.push_back( blankParam );
1829                 }
1830             }
1832             // Now push our munged params to be the new argv and argc
1833             {
1834                 char** block = new char*[newArgs.size()];
1835                 int iz = 0;
1836                 for ( std::vector<char*>::iterator it = newArgs.begin(); it != newArgs.end(); it++ )
1837                 {
1838                     block[iz++] = *it;
1839                 }
1840                 argv = block;
1841                 argc = newArgs.size();
1842                 worked = true;
1843             }
1844         }
1845 #ifdef REPLACEARGS_DEBUG
1846         else
1847         {
1848             MessageBoxA( NULL, "Unable to process command-line", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1849         }
1850 #endif // REPLACEARGS_DEBUG
1851     }
1852 #ifdef REPLACEARGS_DEBUG
1853     else
1854     {
1855         {
1856             MessageBoxA( NULL,  "Unable to fetch result from GetCommandLineW()", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1857         }
1859         char* line2 = GetCommandLineA();
1860         if ( line2 )
1861         {
1862             gchar *safe = Inkscape::IO::sanitizeString(line2);
1863             {
1864                 {
1865                     char tmp[strlen(safe) + 32];
1866                     snprintf( tmp, sizeof(tmp), "GetCommandLineA() = '%s'", safe );
1867                     MessageBoxA( NULL, tmp, "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1868                 }
1869             }
1870         }
1871         else
1872         {
1873             MessageBoxA( NULL, "Unable to fetch result from GetCommandLineA()", "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1874         }
1875     }
1876 #endif // REPLACEARGS_DEBUG
1878     return worked;
1880 #endif // WIN32
1882 static GSList *
1883 sp_process_args(poptContext ctx)
1885     GSList *fl = NULL;
1887     gint a;
1888     while ((a = poptGetNextOpt(ctx)) != -1) {
1889         switch (a) {
1890             case SP_ARG_FILE: {
1891                 gchar const *fn = poptGetOptArg(ctx);
1892                 if (fn != NULL) {
1893                     fl = g_slist_append(fl, g_strdup(fn));
1894                 }
1895                 break;
1896             }
1897             case SP_ARG_VERSION: {
1898                 printf("Inkscape %s (%s)\n", Inkscape::version_string, __DATE__);
1899                 exit(0);
1900                 break;
1901             }
1902             case SP_ARG_EXTENSIONDIR: {
1903                 printf("%s\n", INKSCAPE_EXTENSIONDIR);
1904                 exit(0);
1905                 break;
1906             }
1907             case SP_ARG_VERB_LIST: {
1908                 // This really shouldn't go here, we should init the app.
1909                 // But, since we're just exiting in this path, there is
1910                 // no harm, and this is really a better place to put
1911                 // everything else.
1912                 Inkscape::Extension::init();
1913                 Inkscape::Verb::list();
1914                 exit(0);
1915                 break;
1916             }
1917             case SP_ARG_VERB:
1918             case SP_ARG_SELECT: {
1919                 gchar const *arg = poptGetOptArg(ctx);
1920                 if (arg != NULL) {
1921                     // printf("Adding in: %s\n", arg);
1922                     new Inkscape::CmdLineAction((a == SP_ARG_VERB), arg);
1923                 }
1924                 break;
1925             }
1926             case POPT_ERROR_BADOPT: {
1927                 g_warning ("Invalid option %s", poptBadOption(ctx, 0));
1928                 exit(1);
1929                 break;
1930             }
1931             default: {
1932                 break;
1933             }
1934         }
1935     }
1937     gchar const ** const args = poptGetArgs(ctx);
1938     if (args != NULL) {
1939         for (unsigned i = 0; args[i] != NULL; i++) {
1940             fl = g_slist_append(fl, g_strdup(args[i]));
1941         }
1942     }
1944     return fl;
1948 /*
1949   Local Variables:
1950   mode:c++
1951   c-file-style:"stroustrup"
1952   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1953   indent-tabs-mode:nil
1954   fill-column:99
1955   End:
1956 */
1957 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :