Code

A simple layout document as to what, why and how is cppification.
[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     gchar *new_pythonpath;
549     
550 #ifdef WIN32
551     extdir = g_win32_locale_filename_from_utf8(INKSCAPE_EXTENSIONDIR);
552 #else
553     extdir = g_strdup(INKSCAPE_EXTENSIONDIR);
554 #endif
556     // On some platforms, INKSCAPE_EXTENSIONDIR is not absolute,
557     // but relative to the directory that contains the Inkscape executable.
558     // Since we spawn Python chdir'ed into the script's directory,
559     // we need to obtain the absolute path here.
560     if (!g_path_is_absolute(extdir)) {
561         gchar *curdir = g_get_current_dir();
562         gchar *extdir_new = g_build_filename(curdir, extdir, NULL);
563         g_free(extdir);
564         g_free(curdir);
565         extdir = extdir_new;
566     }
568     if (pythonpath) {
569         new_pythonpath = g_strdup_printf("%s" G_SEARCHPATH_SEPARATOR_S "%s",
570                                          extdir, pythonpath);
571         g_free(extdir);
572     } else {
573         new_pythonpath = extdir;
574     }
576     g_setenv("PYTHONPATH", new_pythonpath, TRUE);
577     g_free(new_pythonpath);
578     //printf("PYTHONPATH = %s\n", g_getenv("PYTHONPATH"));
581 /**
582  * This is the classic main() entry point of the program, though on some
583  * architectures it might be called by something else.
584  */
585 int
586 main(int argc, char **argv)
588 #ifdef HAVE_FPSETMASK
589     /* This is inherited from Sodipodi code, where it was in #ifdef __FreeBSD__.  It's probably
590        safe to remove: the default mask is already 0 in C99, and in current FreeBSD according to
591        the fenv man page on www.freebsd.org, and in glibc according to (libc)FP Exceptions. */
592     fpsetmask(fpgetmask() & ~(FP_X_DZ | FP_X_INV));
593 #endif
595 #ifdef WIN32
596     gchar *exedir = g_strdup(win32_getExePath().data());
597     _win32_set_inkscape_env(exedir);
599 # ifdef ENABLE_NLS
600     // obtain short path to executable dir and pass it
601     // to bindtextdomain (it doesn't understand UTF-8)
602     gchar *shortexedir = g_win32_locale_filename_from_utf8(exedir);
603     gchar *localepath = g_build_filename(shortexedir, PACKAGE_LOCALE_DIR, NULL);
604     bindtextdomain(GETTEXT_PACKAGE, localepath);
605     g_free(shortexedir);
606     g_free(localepath);
607 # endif
608     g_free(exedir);
610     // Don't touch the registry (works fine without it) for Inkscape Portable
611     gchar const *val = g_getenv("INKSCAPE_PORTABLE_PROFILE_DIR");
612     if (!val) {
613         RegistryTool rt;
614         rt.setPathInfo();
615     }
616 #elif defined(ENABLE_NLS)
617 # ifdef ENABLE_BINRELOC
618     bindtextdomain(GETTEXT_PACKAGE, BR_LOCALEDIR(""));
619 # else
620     bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
621 # endif
622 #endif
624     // the bit below compiles regardless of platform
625 #ifdef ENABLE_NLS
626     // Allow the user to override the locale directory by setting
627     // the environment variable INKSCAPE_LOCALEDIR.
628     char const *inkscape_localedir = g_getenv("INKSCAPE_LOCALEDIR");
629     if (inkscape_localedir != NULL) {
630         bindtextdomain(GETTEXT_PACKAGE, inkscape_localedir);
631     }
633     // common setup
634     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
635     textdomain(GETTEXT_PACKAGE);
636 #endif
638     set_extensions_env();
640     // Prevents errors like "Unable to wrap GdkPixbuf..." (in nr-filter-image.cpp for example)
641     Gtk::Main::init_gtkmm_internals();
643     LIBXML_TEST_VERSION
645     Inkscape::GC::init();
647     Inkscape::Debug::Logger::init();
649     gboolean use_gui;
651 #ifndef WIN32
652     use_gui = (g_getenv("DISPLAY") != NULL);
653 #else
654     use_gui = TRUE;
655 #endif
656     /* Test whether with/without GUI is forced */
657     for (int i = 1; i < argc; i++) {
658         if (!strcmp(argv[i], "-z")
659             || !strcmp(argv[i], "--without-gui")
660             || !strcmp(argv[i], "-p")
661             || !strncmp(argv[i], "--print", 7)
662             || !strcmp(argv[i], "-e")
663             || !strncmp(argv[i], "--export-png", 12)
664             || !strcmp(argv[i], "-l")
665             || !strncmp(argv[i], "--export-plain-svg", 18)
666             || !strcmp(argv[i], "-i")
667             || !strncmp(argv[i], "--export-area-drawing", 21)
668             || !strcmp(argv[i], "-D")
669             || !strncmp(argv[i], "--export-area-page", 18)
670             || !strcmp(argv[i], "-C")
671             || !strncmp(argv[i], "--export-id", 11)
672             || !strcmp(argv[i], "-P")
673             || !strncmp(argv[i], "--export-ps", 11)
674             || !strcmp(argv[i], "-E")
675             || !strncmp(argv[i], "--export-eps", 12)
676             || !strcmp(argv[i], "-A")
677             || !strncmp(argv[i], "--export-pdf", 12)
678             || !strncmp(argv[i], "--export-latex", 14)
679 #ifdef WIN32
680             || !strcmp(argv[i], "-M")
681             || !strncmp(argv[i], "--export-emf", 12)
682 #endif //WIN32
683             || !strcmp(argv[i], "-W")
684             || !strncmp(argv[i], "--query-width", 13)
685             || !strcmp(argv[i], "-H")
686             || !strncmp(argv[i], "--query-height", 14)
687             || !strcmp(argv[i], "-S")
688             || !strncmp(argv[i], "--query-all", 11)
689             || !strcmp(argv[i], "-X")
690             || !strncmp(argv[i], "--query-x", 9)
691             || !strcmp(argv[i], "-Y")
692             || !strncmp(argv[i], "--query-y", 9)
693             || !strcmp(argv[i], "--vacuum-defs")
694             || !strcmp(argv[i], "--shell")
695            )
696         {
697             /* main_console handles any exports -- not the gui */
698             use_gui = FALSE;
699             break;
700         } else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "--with-gui")) {
701             use_gui = TRUE;
702             break;
703         }
704     }
706 #ifdef WIN32
707 #ifndef REPLACEARGS_ANSI
708     if ( PrintWin32::is_os_wide() )
709 #endif // REPLACEARGS_ANSI
710     {
711         // If the call fails, we'll need to convert charsets
712         needToRecodeParams = !replaceArgs( argc, argv );
713     }
714 #endif // WIN32
716     /// \todo  Should this be a static object (see inkscape.cpp)?
717     Inkscape::NSApplication::Application app(argc, argv, use_gui, sp_new_gui);
719     return app.run();
725 void fixupSingleFilename( gchar **orig, gchar **spare )
727     if ( orig && *orig && **orig ) {
728         GError *error = NULL;
729         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(*orig, -1, NULL, NULL, &error);
730         if ( newFileName )
731         {
732             *orig = newFileName;
733             if ( spare ) {
734                 *spare = newFileName;
735             }
736 //             g_message("Set a replacement fixup");
737         }
738     }
743 GSList *fixupFilenameEncoding( GSList* fl )
745     GSList *newFl = NULL;
746     while ( fl ) {
747         gchar *fn = static_cast<gchar*>(fl->data);
748         fl = g_slist_remove( fl, fl->data );
749         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(fn, -1, NULL, NULL, NULL);
750         if ( newFileName ) {
752             if ( 0 )
753             {
754                 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
755                 gchar *safeNewFn = Inkscape::IO::sanitizeString(newFileName);
756                 GtkWidget *w = gtk_message_dialog_new( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
757                                                        "Note: Converted '%s' to '%s'", safeFn, safeNewFn );
758                 gtk_dialog_run (GTK_DIALOG (w));
759                 gtk_widget_destroy (w);
760                 g_free(safeNewFn);
761                 g_free(safeFn);
762             }
764             g_free( fn );
765             fn = newFileName;
766             newFileName = 0;
767         }
768         else
769             if ( 0 )
770         {
771             gchar *safeFn = Inkscape::IO::sanitizeString(fn);
772             GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "Error: Unable to convert '%s'", safeFn );
773             gtk_dialog_run (GTK_DIALOG (w));
774             gtk_widget_destroy (w);
775             g_free(safeFn);
776         }
777         newFl = g_slist_append( newFl, fn );
778     }
779     return newFl;
782 int sp_common_main( int argc, char const **argv, GSList **flDest )
784     /// \todo fixme: Move these to some centralized location (Lauris)
785     sp_object_type_register("sodipodi:namedview", SP_TYPE_NAMEDVIEW);
786     sp_object_type_register("sodipodi:guide", SP_TYPE_GUIDE);
789     // temporarily switch gettext encoding to locale, so that help messages can be output properly
790     gchar const *charset;
791     g_get_charset(&charset);
793     bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
795     poptContext ctx = poptGetContext(NULL, argc, argv, options, 0);
796     poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
797     g_return_val_if_fail(ctx != NULL, 1);
799     /* Collect own arguments */
800     GSList *fl = sp_process_args(ctx);
801     poptFreeContext(ctx);
803     // now switch gettext back to UTF-8 (for GUI)
804     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
806     // Now let's see if the file list still holds up
807     if ( needToRecodeParams )
808     {
809         fl = fixupFilenameEncoding( fl );
810     }
812     // Check the globals for filename-fixup
813     if ( needToRecodeParams )
814     {
815         fixupSingleFilename( &sp_export_png, &sp_export_png_utf8 );
816         fixupSingleFilename( &sp_export_svg, &sp_export_svg_utf8 );
817         fixupSingleFilename( &sp_global_printer, &sp_global_printer_utf8 );
818     }
819     else
820     {
821         if ( sp_export_png )
822             sp_export_png_utf8 = g_strdup( sp_export_png );
823         if ( sp_export_svg )
824             sp_export_svg_utf8 = g_strdup( sp_export_svg );
825         if ( sp_global_printer )
826             sp_global_printer_utf8 = g_strdup( sp_global_printer );
827     }
829     // Return the list if wanted, else free it up.
830     if ( flDest ) {
831         *flDest = fl;
832         fl = 0;
833     } else {
834         while ( fl ) {
835             g_free( fl->data );
836             fl = g_slist_remove( fl, fl->data );
837         }
838     }
839     return 0;
842 static void
843 snooper(GdkEvent *event, gpointer /*data*/) {
844     if (inkscape_mapalt())  /* returns the map of the keyboard modifier to map to Alt, zero if no mapping */
845     {
846         GdkModifierType mapping=(GdkModifierType)inkscape_mapalt();
847         switch (event->type) {
848             case GDK_MOTION_NOTIFY:
849                 if(event->motion.state & mapping) {
850                     event->motion.state|=GDK_MOD1_MASK;
851                 }
852                 break;
853             case GDK_BUTTON_PRESS:
854                 if(event->button.state & mapping) {
855                     event->button.state|=GDK_MOD1_MASK;
856                 }
857                 break;
858              case GDK_KEY_PRESS:
859                  if(event->key.state & mapping) {
860                      event->key.state|=GDK_MOD1_MASK;
861                  }
862                  break;
863         default:
864             break;
865         }
866     }
868     if (inkscape_trackalt()) {
869         // MacOS X with X11 has some problem with the default
870         // xmodmapping.  A ~/.xmodmap solution does not work reliably due
871         // to the way we package our executable in a .app that can launch
872         // X11 or use an already-running X11.  The same problem has been
873         // reported on Linux but there is no .app/X11 to get in the way
874         // of ~/.xmodmap fixes.  So we make this a preference.
875         //
876         // For some reason, Gdk senses changes in Alt (Mod1) state for
877         // many message types, but not for keystrokes!  So this ugly hack
878         // tracks what the state of Alt-pressing is, and ensures
879         // GDK_MOD1_MASK is in the event->key.state as appropriate.
880         //
881         static gboolean altL_pressed = FALSE;
882         static gboolean altR_pressed = FALSE;
883         static gboolean alt_pressed = FALSE;
884         guint get_group0_keyval(GdkEventKey* event);
885         guint keyval = 0;
886         switch (event->type) {
887         case GDK_MOTION_NOTIFY:
888             alt_pressed = TRUE && (event->motion.state & GDK_MOD1_MASK);
889             break;
890         case GDK_BUTTON_PRESS:
891             alt_pressed = TRUE && (event->button.state & GDK_MOD1_MASK);
892             break;
893         case GDK_KEY_PRESS:
894             keyval = get_group0_keyval(&event->key);
895             if (keyval == GDK_Alt_L) altL_pressed = TRUE;
896             if (keyval == GDK_Alt_R) altR_pressed = TRUE;
897             alt_pressed = alt_pressed || altL_pressed || altR_pressed;
898             alt_pressed = alt_pressed || (event->button.state & GDK_MOD1_MASK);
899             if (alt_pressed)
900                 event->key.state |= GDK_MOD1_MASK;
901             else
902                 event->key.state &= ~GDK_MOD1_MASK;
903             break;
904         case GDK_KEY_RELEASE:
905             keyval = get_group0_keyval(&event->key);
906             if (keyval == GDK_Alt_L) altL_pressed = FALSE;
907             if (keyval == GDK_Alt_R) altR_pressed = FALSE;
908             if (!altL_pressed && !altR_pressed)
909                 alt_pressed = FALSE;
910             break;
911         default:
912             break;
913         }
914         //printf("alt_pressed: %s\n", alt_pressed? "+" : "-");
915     }
917     gtk_main_do_event (event);
920 static std::vector<Glib::ustring> getDirectorySet(const gchar* userDir, const gchar* const * systemDirs) {
921     std::vector<Glib::ustring> listing;
922     listing.push_back(userDir);
923     for ( const char* const* cur = systemDirs; *cur; cur++ )
924     {
925         listing.push_back(*cur);
926     }
927     return listing;
930 int
931 sp_main_gui(int argc, char const **argv)
933     Gtk::Main main_instance (&argc, const_cast<char ***>(&argv));
935     GSList *fl = NULL;
936     int retVal = sp_common_main( argc, argv, &fl );
937     g_return_val_if_fail(retVal == 0, 1);
939     // Add possible icon entry directories
940     std::vector<Glib::ustring> dataDirs = getDirectorySet( g_get_user_data_dir(),
941                                                            g_get_system_data_dirs() );
942     for (std::vector<Glib::ustring>::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it)
943     {
944         std::vector<Glib::ustring> listing;
945         listing.push_back(*it);
946         listing.push_back("inkscape");
947         listing.push_back("icons");
948         Glib::ustring dir = Glib::build_filename(listing);
949         gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), dir.c_str());
950     }
952     // Add our icon directory to the search path for icon theme lookups.
953     gchar *usericondir = profile_path("icons");
954     gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), usericondir);
955     gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), INKSCAPE_PIXMAPDIR);
956     g_free(usericondir);
958     gdk_event_handler_set((GdkEventFunc)snooper, NULL, NULL);
959     Inkscape::Debug::log_display_config();
961     // Set default window icon. Obeys the theme.
962     gtk_window_set_default_icon_name("inkscape");
963     // Do things that were previously in inkscape_gtk_stock_init().
964     sp_icon_get_phys_size(GTK_ICON_SIZE_MENU);
965     Inkscape::UI::Widget::Panel::prep();
967     gboolean create_new = TRUE;
969     /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
970     inkscape_application_init(argv[0], true);
972     while (fl) {
973         if (sp_file_open((gchar *)fl->data,NULL)) {
974             create_new=FALSE;
975         }
976         fl = g_slist_remove(fl, fl->data);
977     }
978     if (create_new) {
979         sp_file_new_default();
980     }
982     Glib::signal_idle().connect(sigc::ptr_fun(&Inkscape::CmdLineAction::idle));
983     main_instance.run();
985 #ifdef WIN32
986     //We might not need anything here
987     //sp_win32_finish(); <-- this is a NOP func
988 #endif
990     return 0;
993 /**
994  * Process file list
995  */
996 void sp_process_file_list(GSList *fl)
998     while (fl) {
999         const gchar *filename = (gchar *)fl->data;
1001         SPDocument *doc = NULL;
1002         try {
1003             doc = Inkscape::Extension::open(NULL, filename);
1004         } catch (Inkscape::Extension::Input::no_extension_found &e) {
1005             doc = NULL;
1006         } catch (Inkscape::Extension::Input::open_failed &e) {
1007             doc = NULL;
1008         }
1010         if (doc == NULL) {
1011             try {
1012                 doc = Inkscape::Extension::open(Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), filename);
1013             } catch (Inkscape::Extension::Input::no_extension_found &e) {
1014                 doc = NULL;
1015             } catch (Inkscape::Extension::Input::open_failed &e) {
1016                 doc = NULL;
1017             }
1018         }
1019         if (doc == NULL) {
1020             g_warning("Specified document %s cannot be opened (does not exist or not a valid SVG file)", filename);
1021         } else {
1022             if (sp_vacuum_defs) {
1023                 doc->vacuum_document();
1024             }
1025             if (sp_vacuum_defs && !sp_export_svg) {
1026                 // save under the name given in the command line
1027                 sp_repr_save_file(doc->rdoc, filename, SP_SVG_NS_URI);
1028             }
1029             if (sp_global_printer) {
1030                 sp_print_document_to_file(doc, sp_global_printer);
1031             }
1032             if (sp_export_png || (sp_export_id && sp_export_use_hints)) {
1033                 sp_do_export_png(doc);
1034             }
1035             if (sp_export_svg) {
1036                 Inkscape::XML::Document *rdoc;
1037                 Inkscape::XML::Node *repr;
1038                 rdoc = sp_repr_document_new("svg:svg");
1039                 repr = rdoc->root();
1040                 repr = sp_document_root(doc)->updateRepr(rdoc, repr, SP_OBJECT_WRITE_BUILD);
1041                 sp_repr_save_rebased_file(repr->document(), sp_export_svg, SP_SVG_NS_URI,
1042                                           doc->base, sp_export_svg);
1043             }
1044             if (sp_export_ps) {
1045                 do_export_ps_pdf(doc, sp_export_ps, "image/x-postscript");
1046             }
1047             if (sp_export_eps) {
1048                 do_export_ps_pdf(doc, sp_export_eps, "image/x-e-postscript");
1049             }
1050             if (sp_export_pdf) {
1051                 do_export_ps_pdf(doc, sp_export_pdf, "application/pdf");
1052             }
1053 #ifdef WIN32
1054             if (sp_export_emf) {
1055                 do_export_emf(doc, sp_export_emf, "image/x-emf");
1056             }
1057 #endif //WIN32
1058             if (sp_query_all) {
1059                 do_query_all (doc);
1060             } else if (sp_query_width || sp_query_height) {
1061                 do_query_dimension (doc, true, sp_query_width? Geom::X : Geom::Y, sp_query_id);
1062             } else if (sp_query_x || sp_query_y) {
1063                 do_query_dimension (doc, false, sp_query_x? Geom::X : Geom::Y, sp_query_id);
1064             }
1066             delete doc;
1067         }
1068         fl = g_slist_remove(fl, fl->data);
1069     }
1072 /**
1073  * Run the application as an interactive shell, parsing command lines from stdin
1074  * Returns -1 on error.
1075  */
1076 int sp_main_shell(char const* command_name)
1078     int retval = 0;
1080     const unsigned int buffer_size = 4096;
1081     gchar *command_line = g_strnfill(buffer_size, 0);
1082     g_strlcpy(command_line, command_name, buffer_size);
1083     gsize offset = g_strlcat(command_line, " ", buffer_size);
1084     gsize sizeLeft = buffer_size - offset;
1085     gchar *useme = command_line + offset;
1087     fprintf(stdout, "Inkscape %s interactive shell mode. Type 'quit' to quit.\n", Inkscape::version_string);
1088     fflush(stdout);
1089     char* linedata = 0;
1090     do {
1091         fprintf(stdout, ">");
1092         fflush(stdout);
1093         if ((linedata = fgets(useme, sizeLeft, stdin))) {
1094             size_t len = strlen(useme);
1095             if ( (len >= sizeLeft - 1) || (useme[len - 1] != '\n') ) {
1096                 fprintf(stdout, "ERROR: Command line too long\n");
1097                 // Consume rest of line
1098                 retval = -1; // If the while loop completes, this remains -1
1099                 while (fgets(useme, sizeLeft, stdin) && retval) {
1100                     len = strlen(command_line);
1101                     if ( (len < buffer_size) && (command_line[len-1] == '\n') ) {
1102                         retval = 0;
1103                     }
1104                 }
1105             } else {
1106                 useme[--len] = '\0';  // Strip newline
1107                 if (useme[len - 1] == '\r') {
1108                     useme[--len] = '\0';
1109                 }
1110                 if ( strcmp(useme, "quit") == 0 ) {
1111                     // Time to quit
1112                     fflush(stdout);
1113                     linedata = 0; // mark for exit
1114                 } else if ( len < 1 ) {
1115                     // blank string. Do nothing.
1116                 } else {
1117                     GError* parseError = 0;
1118                     gchar** argv = 0;
1119                     gint argc = 0;
1120                     if ( g_shell_parse_argv(command_line, &argc, &argv, &parseError) ) {
1121                         poptContext ctx = poptGetContext(NULL, argc, const_cast<const gchar**>(argv), options, 0);
1122                         poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
1123                         if ( ctx ) {
1124                             GSList *fl = sp_process_args(ctx);
1125                             sp_process_file_list(fl);
1126                             poptFreeContext(ctx);
1127                         } else {
1128                             retval = 1; // not sure why. But this was the previous return value
1129                         }
1130                         resetCommandlineGlobals();
1131                         g_strfreev(argv);
1132                     } else {
1133                         g_warning("Cannot parse commandline: %s", useme);
1134                     }
1135                 }
1136             }
1137         } // if (linedata...
1138     } while (linedata && (retval == 0));
1140     g_free(command_line);
1141     return retval;
1144 int sp_main_console(int argc, char const **argv)
1146     /* We are started in text mode */
1148     /* Do this g_type_init(), so that we can use Xft/Freetype2 (Pango)
1149      * in a non-Gtk environment.  Used in libnrtype's
1150      * FontInstance.cpp and FontFactory.cpp.
1151      * http://mail.gnome.org/archives/gtk-list/2003-December/msg00063.html
1152      */
1153     g_type_init();
1154     char **argv2 = const_cast<char **>(argv);
1155     gtk_init_check( &argc, &argv2 );
1156     //setlocale(LC_ALL, "");
1158     GSList *fl = NULL;
1159     int retVal = sp_common_main( argc, argv, &fl );
1160     g_return_val_if_fail(retVal == 0, 1);
1162     if (fl == NULL && !sp_shell) {
1163         g_print("Nothing to do!\n");
1164         exit(0);
1165     }
1167     inkscape_application_init(argv[0], false);
1169     if (sp_shell) {
1170         sp_main_shell(argv[0]); // Run as interactive shell
1171         exit(0);
1172     } else {
1173         sp_process_file_list(fl); // Normal command line invokation
1174     }
1176     return 0;
1179 static void
1180 do_query_dimension (SPDocument *doc, bool extent, Geom::Dim2 const axis, const gchar *id)
1182     SPObject *o = NULL;
1184     if (id) {
1185         o = doc->getObjectById(id);
1186         if (o) {
1187             if (!SP_IS_ITEM (o)) {
1188                 g_warning("Object with id=\"%s\" is not a visible item. Cannot query dimensions.", id);
1189                 return;
1190             }
1191         } else {
1192             g_warning("Object with id=\"%s\" is not found. Cannot query dimensions.", id);
1193             return;
1194         }
1195     } else {
1196         o = SP_DOCUMENT_ROOT(doc);
1197     }
1199     if (o) {
1200         doc->ensure_up_to_date ();
1201         SPItem *item = ((SPItem *) o);
1203         // "true" SVG bbox for scripting
1204         Geom::OptRect area = item->getBounds(item->i2doc_affine());
1205         if (area) {
1206             Inkscape::SVGOStringStream os;
1207             if (extent) {
1208                 os << area->dimensions()[axis];
1209             } else {
1210                 os << area->min()[axis];
1211             }
1212             g_print ("%s", os.str().c_str());
1213         } else {
1214             g_print("0");
1215         }
1216     }
1219 static void
1220 do_query_all (SPDocument *doc)
1222     SPObject *o = NULL;
1224     o = SP_DOCUMENT_ROOT(doc);
1226     if (o) {
1227         doc->ensure_up_to_date ();
1228         do_query_all_recurse(o);
1229     }
1232 static void
1233 do_query_all_recurse (SPObject *o)
1235     SPItem *item = ((SPItem *) o);
1236     if (o->getId() && SP_IS_ITEM(item)) {
1237         Geom::OptRect area = item->getBounds(item->i2doc_affine());
1238         if (area) {
1239             Inkscape::SVGOStringStream os;
1240             os << o->getId();
1241             os << "," << area->min()[Geom::X];
1242             os << "," << area->min()[Geom::Y];
1243             os << "," << area->dimensions()[Geom::X];
1244             os << "," << area->dimensions()[Geom::Y];
1245             g_print ("%s\n", os.str().c_str());
1246         }
1247     }
1249     SPObject *child = o->children;
1250     while (child) {
1251         do_query_all_recurse (child);
1252         child = child->next;
1253     }
1257 static void
1258 sp_do_export_png(SPDocument *doc)
1260     const gchar *filename = NULL;
1261     bool filename_from_hint = false;
1262     gdouble dpi = 0.0;
1264     if (sp_export_use_hints && (!sp_export_id && !sp_export_area_drawing)) {
1265         g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored.");
1266     }
1268     GSList *items = NULL;
1270     Geom::Rect area;
1271     if (sp_export_id || sp_export_area_drawing) {
1273         SPObject *o = NULL;
1274         SPObject *o_area = NULL;
1275         if (sp_export_id && sp_export_area_drawing) {
1276             o = doc->getObjectById(sp_export_id);
1277             o_area = SP_DOCUMENT_ROOT (doc);
1278         } else if (sp_export_id) {
1279             o = doc->getObjectById(sp_export_id);
1280             o_area = o;
1281         } else if (sp_export_area_drawing) {
1282             o = SP_DOCUMENT_ROOT (doc);
1283             o_area = o;
1284         }
1286         if (o) {
1287             if (!SP_IS_ITEM (o)) {
1288                 g_warning("Object with id=\"%s\" is not a visible item. Nothing exported.", sp_export_id);
1289                 return;
1290             }
1292             items = g_slist_prepend (items, SP_ITEM(o));
1294             if (sp_export_id_only) {
1295                 g_print("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id);
1296             }
1298             if (sp_export_use_hints) {
1300                 // retrieve export filename hint
1301                 const gchar *fn_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-filename");
1302                 if (fn_hint) {
1303                     if (sp_export_png) {
1304                         g_warning ("Using export filename from the command line (--export-png). Filename hint %s is ignored.", fn_hint);
1305                         filename = sp_export_png;
1306                     } else {
1307                         filename = fn_hint;
1308                         filename_from_hint = true;
1309                     }
1310                 } else {
1311                     g_warning ("Export filename hint not found for the object.");
1312                     filename = sp_export_png;
1313                 }
1315                 // retrieve export dpi hints
1316                 const gchar *dpi_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
1317                 if (dpi_hint) {
1318                     if (sp_export_dpi || sp_export_width || sp_export_height) {
1319                         g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint);
1320                     } else {
1321                         dpi = atof(dpi_hint);
1322                     }
1323                 } else {
1324                     g_warning ("Export DPI hint not found for the object.");
1325                 }
1327             }
1329             // write object bbox to area
1330             doc->ensure_up_to_date ();
1331             Geom::OptRect areaMaybe;
1332             static_cast<SPItem *>(o_area)->invoke_bbox( areaMaybe, static_cast<SPItem *>(o_area)->i2d_affine(), TRUE);
1333             if (areaMaybe) {
1334                 area = *areaMaybe;
1335             } else {
1336                 g_warning("Unable to determine a valid bounding box. Nothing exported.");
1337                 return;
1338             }
1339         } else {
1340             g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
1341             return;
1342         }
1343     }
1345     if (sp_export_area) {
1346         /* Try to parse area (given in SVG pixels) */
1347         gdouble x0,y0,x1,y1;
1348         if (!sscanf(sp_export_area, "%lg:%lg:%lg:%lg", &x0, &y0, &x1, &y1) == 4) {
1349             g_warning("Cannot parse export area '%s'; use 'x0:y0:x1:y1'. Nothing exported.", sp_export_area);
1350             return;
1351         }
1352         area = Geom::Rect(Geom::Interval(x0,x1), Geom::Interval(y0,y1));
1353     } else if (sp_export_area_page || !(sp_export_id || sp_export_area_drawing)) {
1354         /* Export the whole page: note: Inkscape uses 'page' in all menus and dialogs, not 'canvas' */
1355         doc->ensure_up_to_date ();
1356         Geom::Point origin (SP_ROOT(doc->root)->x.computed, SP_ROOT(doc->root)->y.computed);
1357         area = Geom::Rect(origin, origin + doc->getDimensions());
1358     }
1360     // set filename and dpi from options, if not yet set from the hints
1361     if (!filename) {
1362         if (!sp_export_png) {
1363             g_warning ("No export filename given and no filename hint. Nothing exported.");
1364             return;
1365         }
1366         filename = sp_export_png;
1367     }
1369     if (sp_export_dpi && dpi == 0.0) {
1370         dpi = atof(sp_export_dpi);
1371         if ((dpi < 0.1) || (dpi > 10000.0)) {
1372             g_warning("DPI value %s out of range [0.1 - 10000.0]. Nothing exported.", sp_export_dpi);
1373             return;
1374         }
1375         g_print("DPI: %g\n", dpi);
1376     }
1378     if (sp_export_area_snap) {
1379         round_rectangle_outwards(area);
1380     }
1382     // default dpi
1383     if (dpi == 0.0) {
1384         dpi = PX_PER_IN;
1385     }
1387     unsigned long int width = 0;
1388     unsigned long int height = 0;
1390     if (sp_export_width) {
1391         errno=0;
1392         width = strtoul(sp_export_width, NULL, 0);
1393         if ((width < 1) || (width > PNG_UINT_31_MAX) || (errno == ERANGE) ) {
1394             g_warning("Export width %lu out of range (1 - %lu). Nothing exported.", width, (unsigned long int)PNG_UINT_31_MAX);
1395             return;
1396         }
1397         dpi = (gdouble) width * PX_PER_IN / area.width();
1398     }
1400     if (sp_export_height) {
1401         errno=0;
1402         height = strtoul(sp_export_height, NULL, 0);
1403         if ((height < 1) || (height > PNG_UINT_31_MAX)) {
1404             g_warning("Export height %lu out of range (1 - %lu). Nothing exported.", height, (unsigned long int)PNG_UINT_31_MAX);
1405             return;
1406         }
1407         dpi = (gdouble) height * PX_PER_IN / area.height();
1408     }
1410     if (!sp_export_width) {
1411         width = (unsigned long int) (area.width() * dpi / PX_PER_IN + 0.5);
1412     }
1414     if (!sp_export_height) {
1415         height = (unsigned long int) (area.height() * dpi / PX_PER_IN + 0.5);
1416     }
1418     guint32 bgcolor = 0x00000000;
1419     if (sp_export_background) {
1420         // override the page color
1421         bgcolor = sp_svg_read_color(sp_export_background, 0xffffff00);
1422         bgcolor |= 0xff; // default is no opacity
1423     } else {
1424         // read from namedview
1425         Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
1426         if (nv && nv->attribute("pagecolor"))
1427             bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
1428         if (nv && nv->attribute("inkscape:pageopacity"))
1429             bgcolor |= SP_COLOR_F_TO_U(sp_repr_get_double_attribute (nv, "inkscape:pageopacity", 1.0));
1430     }
1432     if (sp_export_background_opacity) {
1433         // override opacity
1434         gfloat value;
1435         if (sp_svg_number_read_f (sp_export_background_opacity, &value)) {
1436             if (value > 1.0) {
1437                 value = CLAMP (value, 1.0f, 255.0f);
1438                 bgcolor &= (guint32) 0xffffff00;
1439                 bgcolor |= (guint32) floor(value);
1440             } else {
1441                 value = CLAMP (value, 0.0f, 1.0f);
1442                 bgcolor &= (guint32) 0xffffff00;
1443                 bgcolor |= SP_COLOR_F_TO_U(value);
1444             }
1445         }
1446     }
1448     gchar *path = 0;
1449     if (filename_from_hint) {
1450         //Make relative paths go from the document location, if possible:
1451         if (!g_path_is_absolute(filename) && doc->uri) {
1452             gchar *dirname = g_path_get_dirname(doc->uri);
1453             if (dirname) {
1454                 path = g_build_filename(dirname, filename, NULL);
1455                 g_free(dirname);
1456             }
1457         }
1458         if (!path) {
1459             path = g_strdup(filename);
1460         }
1461     } else {
1462         path = g_strdup(filename);
1463     }
1465     g_print("Background RRGGBBAA: %08x\n", bgcolor);
1467     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);
1469     g_print("Bitmap saved as: %s\n", filename);
1471     if ((width >= 1) && (height >= 1) && (width <= PNG_UINT_31_MAX) && (height <= PNG_UINT_31_MAX)) {
1472         sp_export_png_file(doc, path, area, width, height, dpi, dpi, bgcolor, NULL, NULL, true, sp_export_id_only ? items : NULL);
1473     } else {
1474         g_warning("Calculated bitmap dimensions %lu %lu are out of range (1 - %lu). Nothing exported.", width, height, (unsigned long int)PNG_UINT_31_MAX);
1475     }
1477     g_free (path);
1478     g_slist_free (items);
1482 /**
1483  *  Perform a PDF/PS/EPS export
1484  *
1485  *  \param doc Document to export.
1486  *  \param uri URI to export to.
1487  *  \param mime MIME type to export as.
1488  */
1490 static void do_export_ps_pdf(SPDocument* doc, gchar const* uri, char const* mime)
1492     Inkscape::Extension::DB::OutputList o;
1493     Inkscape::Extension::db.get_output_list(o);
1494     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1495     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1496         i++;
1497     }
1499     if (i == o.end())
1500     {
1501         g_warning ("Could not find an extension to export to MIME type %s.", mime);
1502         return;
1503     }
1505     if (sp_export_id) {
1506         SPObject *o = doc->getObjectById(sp_export_id);
1507         if (o == NULL) {
1508             g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
1509             return;
1510         }
1511         (*i)->set_param_string ("exportId", sp_export_id);
1512     } else {
1513         (*i)->set_param_string ("exportId", "");
1514     }
1516     if (sp_export_area_page && sp_export_area_drawing) {
1517         g_warning ("You cannot use --export-area-page and --export-area-drawing at the same time; only the former will take effect.");
1518         sp_export_area_drawing = false;
1519     }
1521     if (sp_export_area_drawing) {
1522         (*i)->set_param_bool ("areaDrawing", TRUE);
1523     } else {
1524         (*i)->set_param_bool ("areaDrawing", FALSE);
1525     }
1527     if (sp_export_area_page) {
1528         if (sp_export_eps) {
1529             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.");
1530         }
1531         (*i)->set_param_bool ("areaPage", TRUE);
1532     } else {
1533         (*i)->set_param_bool ("areaPage", FALSE);
1534     }
1536     if (!sp_export_area_drawing && !sp_export_area_page && !sp_export_id) {
1537         // neither is set, set page as default for ps/pdf and drawing for eps
1538         if (sp_export_eps) {
1539             try {
1540                (*i)->set_param_bool("areaDrawing", TRUE);
1541             } catch (...) {}
1542         }
1543     }
1545     if (sp_export_text_to_path) {
1546         (*i)->set_param_bool("textToPath", TRUE);
1547     } else {
1548         (*i)->set_param_bool("textToPath", FALSE);
1549     }
1551     if (sp_export_latex) {
1552         (*i)->set_param_bool("textToLaTeX", TRUE);
1553     } else {
1554         (*i)->set_param_bool("textToLaTeX", FALSE);
1555     }
1557     if (sp_export_ignore_filters) {
1558         (*i)->set_param_bool("blurToBitmap", FALSE);
1559     } else {
1560         (*i)->set_param_bool("blurToBitmap", TRUE);
1562         gdouble dpi = 90.0;
1563         if (sp_export_dpi) {
1564             dpi = atof(sp_export_dpi);
1565             if ((dpi < 1) || (dpi > 10000.0)) {
1566                 g_warning("DPI value %s out of range [1 - 10000]. Using 90 dpi instead.", sp_export_dpi);
1567                 dpi = 90;
1568             }
1569         }
1571         (*i)->set_param_int("resolution", (int) dpi);
1572     }
1574     (*i)->save(doc, uri);
1577 #ifdef WIN32
1578 /**
1579  *  Export a document to EMF
1580  *
1581  *  \param doc Document to export.
1582  *  \param uri URI to export to.
1583  *  \param mime MIME type to export as (should be "image/x-emf")
1584  */
1586 static void do_export_emf(SPDocument* doc, gchar const* uri, char const* mime)
1588     Inkscape::Extension::DB::OutputList o;
1589     Inkscape::Extension::db.get_output_list(o);
1590     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1591     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1592         i++;
1593     }
1595     if (i == o.end())
1596     {
1597         g_warning ("Could not find an extension to export to MIME type %s.", mime);
1598         return;
1599     }
1601     (*i)->save(doc, uri);
1603 #endif //WIN32
1605 #ifdef WIN32
1606 bool replaceArgs( int& argc, char**& argv )
1608     bool worked = false;
1610 #ifdef REPLACEARGS_DEBUG
1611     MessageBoxA( NULL, "GetCommandLineW() getting called", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1612 #endif // REPLACEARGS_DEBUG
1614     wchar_t* line = GetCommandLineW();
1615     if ( line )
1616     {
1617 #ifdef REPLACEARGS_DEBUG
1618         {
1619             gchar* utf8Line = g_utf16_to_utf8( (gunichar2*)line, -1, NULL, NULL, NULL );
1620             if ( utf8Line )
1621             {
1622                 gchar *safe = Inkscape::IO::sanitizeString(utf8Line);
1623                 {
1624                     char tmp[strlen(safe) + 32];
1625                     snprintf( tmp, sizeof(tmp), "GetCommandLineW() = '%s'", safe );
1626                     MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1627                 }
1628             }
1629         }
1630 #endif // REPLACEARGS_DEBUG
1632         int numArgs = 0;
1633         wchar_t** parsed = CommandLineToArgvW( line, &numArgs );
1635 #ifdef REPLACEARGS_ANSI
1636 // test code for trying things on Win95/98/ME
1637         if ( !parsed )
1638         {
1639 #ifdef REPLACEARGS_DEBUG
1640             MessageBoxA( NULL, "Unable to process command-line. Faking it", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1641 #endif // REPLACEARGS_DEBUG
1642             int lineLen = wcslen(line) + 1;
1643             wchar_t* lineDup = new wchar_t[lineLen];
1644             wcsncpy( lineDup, line, lineLen );
1646             int pos = 0;
1647             bool inQuotes = false;
1648             bool inWhitespace = true;
1649             std::vector<int> places;
1650             while ( lineDup[pos] )
1651             {
1652                 if ( inQuotes )
1653                 {
1654                     if ( lineDup[pos] == L'"' )
1655                     {
1656                         inQuotes = false;
1657                     }
1658                 }
1659                 else if ( lineDup[pos] == L'"' )
1660                 {
1661                     inQuotes = true;
1662                     inWhitespace = false;
1663                     places.push_back(pos);
1664                 }
1665                 else if ( lineDup[pos] == L' ' || lineDup[pos] == L'\t' )
1666                 {
1667                     if ( !inWhitespace )
1668                     {
1669                         inWhitespace = true;
1670                         lineDup[pos] = 0;
1671                     }
1672                 }
1673                 else if ( inWhitespace && (lineDup[pos] != L' ' && lineDup[pos] != L'\t') )
1674                 {
1675                     inWhitespace = false;
1676                     places.push_back(pos);
1677                 }
1678                 else
1679                 {
1680                     // consume
1681                 }
1682                 pos++;
1683             }
1684 #ifdef REPLACEARGS_DEBUG
1685             {
1686                 char tmp[256];
1687                 snprintf( tmp, sizeof(tmp), "Counted %d args", places.size() );
1688                 MessageBoxA( NULL, tmp, "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1689             }
1690 #endif // REPLACEARGS_DEBUG
1692             wchar_t** block = new wchar_t*[places.size()];
1693             int i = 0;
1694             for ( std::vector<int>::iterator it = places.begin(); it != places.end(); it++ )
1695             {
1696                 block[i++] = &lineDup[*it];
1697             }
1698             parsed = block;
1699             numArgs = places.size();
1700         }
1701 #endif // REPLACEARGS_ANSI
1703         if ( parsed )
1704         {
1705             std::vector<wchar_t*>expandedArgs;
1706             if ( numArgs > 0 )
1707             {
1708                 expandedArgs.push_back( parsed[0] );
1709             }
1711             for ( int i1 = 1; i1 < numArgs; i1++ )
1712             {
1713                 bool wildcarded = (wcschr(parsed[i1], L'?') != NULL) || (wcschr(parsed[i1], L'*') != NULL);
1714                 wildcarded &= parsed[i1][0] != L'"';
1715                 wildcarded &= parsed[i1][0] != L'-';
1716                 if ( wildcarded )
1717                 {
1718 #ifdef REPLACEARGS_ANSI
1719                     WIN32_FIND_DATAA data;
1720 #else
1721                     WIN32_FIND_DATAW data;
1722 #endif // REPLACEARGS_ANSI
1724                     memset((void *)&data, 0, sizeof(data));
1726                     int baseLen = wcslen(parsed[i1]) + 2;
1727                     wchar_t* base = new wchar_t[baseLen];
1728                     wcsncpy( base, parsed[i1], baseLen );
1729                     wchar_t* last = wcsrchr( base, L'\\' );
1730                     if ( last )
1731                     {
1732                         last[1] = 0;
1733                     }
1734                     else
1735                     {
1736                         base[0] = 0;
1737                     }
1738                     baseLen = wcslen( base );
1740 #ifdef REPLACEARGS_ANSI
1741                     char target[MAX_PATH];
1742                     if ( WideCharToMultiByte( CP_ACP, 0, parsed[i1], -1, target, sizeof(target), NULL, NULL) )
1743                     {
1744                         HANDLE hf = FindFirstFileA( target, &data );
1745 #else
1746                         HANDLE hf = FindFirstFileW( parsed[i1], &data );
1747 #endif // REPLACEARGS_ANSI
1748                         if ( hf != INVALID_HANDLE_VALUE )
1749                         {
1750                             BOOL found = TRUE;
1751                             do
1752                             {
1753 #ifdef REPLACEARGS_ANSI
1754                                 int howMany = MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, NULL, 0 );
1755                                 if ( howMany > 0 )
1756                                 {
1757                                     howMany += baseLen;
1758                                     wchar_t* tmp = new wchar_t[howMany + 1];
1759                                     wcsncpy( tmp, base, howMany + 1 );
1760                                     MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, tmp + baseLen, howMany + 1 - baseLen );
1761                                     expandedArgs.push_back( tmp );
1762                                     found = FindNextFileA( hf, &data );
1763                                 }
1764 #else
1765                                 int howMany = wcslen(data.cFileName) + baseLen;
1766                                 wchar_t* tmp = new wchar_t[howMany + 1];
1767                                 wcsncpy( tmp, base, howMany + 1 );
1768                                 wcsncat( tmp, data.cFileName, howMany + 1 );
1769                                 expandedArgs.push_back( tmp );
1770                                 found = FindNextFileW( hf, &data );
1771 #endif // REPLACEARGS_ANSI
1772                             } while ( found );
1774                             FindClose( hf );
1775                         }
1776                         else
1777                         {
1778                             expandedArgs.push_back( parsed[i1] );
1779                         }
1780 #ifdef REPLACEARGS_ANSI
1781                     }
1782 #endif // REPLACEARGS_ANSI
1784                     delete[] base;
1785                 }
1786                 else
1787                 {
1788                     expandedArgs.push_back( parsed[i1] );
1789                 }
1790             }
1792             {
1793                 wchar_t** block = new wchar_t*[expandedArgs.size()];
1794                 int iz = 0;
1795                 for ( std::vector<wchar_t*>::iterator it = expandedArgs.begin(); it != expandedArgs.end(); it++ )
1796                 {
1797                     block[iz++] = *it;
1798                 }
1799                 parsed = block;
1800                 numArgs = expandedArgs.size();
1801             }
1803             std::vector<gchar*> newArgs;
1804             for ( int i = 0; i < numArgs; i++ )
1805             {
1806                 gchar* replacement = g_utf16_to_utf8( (gunichar2*)parsed[i], -1, NULL, NULL, NULL );
1807                 if ( replacement )
1808                 {
1809 #ifdef REPLACEARGS_DEBUG
1810                     gchar *safe2 = Inkscape::IO::sanitizeString(replacement);
1812                     if ( safe2 )
1813                     {
1814                         {
1815                             char tmp[1024];
1816                             snprintf( tmp, sizeof(tmp), "    [%2d] = '%s'", i, safe2 );
1817                             MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1818                         }
1819                         g_free( safe2 );
1820                     }
1821 #endif // REPLACEARGS_DEBUG
1823                     newArgs.push_back( replacement );
1824                 }
1825                 else
1826                 {
1827                     newArgs.push_back( blankParam );
1828                 }
1829             }
1831             // Now push our munged params to be the new argv and argc
1832             {
1833                 char** block = new char*[newArgs.size()];
1834                 int iz = 0;
1835                 for ( std::vector<char*>::iterator it = newArgs.begin(); it != newArgs.end(); it++ )
1836                 {
1837                     block[iz++] = *it;
1838                 }
1839                 argv = block;
1840                 argc = newArgs.size();
1841                 worked = true;
1842             }
1843         }
1844 #ifdef REPLACEARGS_DEBUG
1845         else
1846         {
1847             MessageBoxA( NULL, "Unable to process command-line", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1848         }
1849 #endif // REPLACEARGS_DEBUG
1850     }
1851 #ifdef REPLACEARGS_DEBUG
1852     else
1853     {
1854         {
1855             MessageBoxA( NULL,  "Unable to fetch result from GetCommandLineW()", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1856         }
1858         char* line2 = GetCommandLineA();
1859         if ( line2 )
1860         {
1861             gchar *safe = Inkscape::IO::sanitizeString(line2);
1862             {
1863                 {
1864                     char tmp[strlen(safe) + 32];
1865                     snprintf( tmp, sizeof(tmp), "GetCommandLineA() = '%s'", safe );
1866                     MessageBoxA( NULL, tmp, "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1867                 }
1868             }
1869         }
1870         else
1871         {
1872             MessageBoxA( NULL, "Unable to fetch result from GetCommandLineA()", "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1873         }
1874     }
1875 #endif // REPLACEARGS_DEBUG
1877     return worked;
1879 #endif // WIN32
1881 static GSList *
1882 sp_process_args(poptContext ctx)
1884     GSList *fl = NULL;
1886     gint a;
1887     while ((a = poptGetNextOpt(ctx)) != -1) {
1888         switch (a) {
1889             case SP_ARG_FILE: {
1890                 gchar const *fn = poptGetOptArg(ctx);
1891                 if (fn != NULL) {
1892                     fl = g_slist_append(fl, g_strdup(fn));
1893                 }
1894                 break;
1895             }
1896             case SP_ARG_VERSION: {
1897                 printf("Inkscape %s (%s)\n", Inkscape::version_string, __DATE__);
1898                 exit(0);
1899                 break;
1900             }
1901             case SP_ARG_EXTENSIONDIR: {
1902                 printf("%s\n", INKSCAPE_EXTENSIONDIR);
1903                 exit(0);
1904                 break;
1905             }
1906             case SP_ARG_VERB_LIST: {
1907                 // This really shouldn't go here, we should init the app.
1908                 // But, since we're just exiting in this path, there is
1909                 // no harm, and this is really a better place to put
1910                 // everything else.
1911                 Inkscape::Extension::init();
1912                 Inkscape::Verb::list();
1913                 exit(0);
1914                 break;
1915             }
1916             case SP_ARG_VERB:
1917             case SP_ARG_SELECT: {
1918                 gchar const *arg = poptGetOptArg(ctx);
1919                 if (arg != NULL) {
1920                     // printf("Adding in: %s\n", arg);
1921                     new Inkscape::CmdLineAction((a == SP_ARG_VERB), arg);
1922                 }
1923                 break;
1924             }
1925             case POPT_ERROR_BADOPT: {
1926                 g_warning ("Invalid option %s", poptBadOption(ctx, 0));
1927                 exit(1);
1928                 break;
1929             }
1930             default: {
1931                 break;
1932             }
1933         }
1934     }
1936     gchar const ** const args = poptGetArgs(ctx);
1937     if (args != NULL) {
1938         for (unsigned i = 0; args[i] != NULL; i++) {
1939             fl = g_slist_append(fl, g_strdup(args[i]));
1940         }
1941     }
1943     return fl;
1947 /*
1948   Local Variables:
1949   mode:c++
1950   c-file-style:"stroustrup"
1951   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1952   indent-tabs-mode:nil
1953   fill-column:99
1954   End:
1955 */
1956 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :