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