50#include <giomm/file.h>
51#include <glibmm/i18n.h>
52#include <gtkmm/application.h>
53#include <gtkmm/recentmanager.h>
107#ifdef WITH_GNU_READLINE
108#include <readline/readline.h>
109#include <readline/history.h>
123 auto [it, inserted] =
_documents.try_emplace(std::move(document));
125 INKSCAPE.add_document(it->first.get());
126 return it->first.get();
132 if (template_filename.empty()) {
142 std::cerr <<
"InkscapeApplication::new_document: failed to open new document!" << std::endl;
149 if (!doc->getRoot()->viewBox_set) {
162 return {
nullptr,
true};
165 std::cerr <<
"InkscapeApplication::document_open: Failed to open: " << file->get_parse_name().raw() << std::endl;
166 return {
nullptr,
false};
169 document->setVirgin(
false);
173 if (
auto recentmanager = Gtk::RecentManager::get_default()) {
174 auto uri = file->get_uri();
175 auto path = file->get_path();
178 bool is_crash =
false;
180 auto orig = recentmanager->lookup_item(uri);
181 is_crash =
orig->has_group(
"Crash");
183 document->setModifiedSinceSave(
true);
186 document->setDocumentFilename(old_path.empty() ?
nullptr : old_path.c_str());
188 recentmanager->remove_item(uri);
190 }
catch (Glib::Error
const &) {
194 recentmanager->add_item(uri);
208 std::cerr <<
"InkscapeApplication::document_open: Failed to open memory document." << std::endl;
212 document->setVirgin(
false);
225 std::cerr <<
"InkscapeAppliation::swap_document: Missing desktop or document!" << std::endl;
237 std::cerr <<
"InkscapeApplication::swap_document: Old document not in map!" << std::endl;
242 auto dt_it = std::find_if(doc_it->second.begin(), doc_it->second.end(), [=] (
auto &dt) { return dt.get() == desktop; });
243 if (dt_it == doc_it->second.end()) {
244 std::cerr <<
"InkscapeApplication::swap_document: Desktop not found!" << std::endl;
248 auto dt_uniq = std::move(*dt_it);
249 doc_it->second.erase(dt_it);
254 std::cerr <<
"InkscapeApplication::swap_document: New document not in map!" << std::endl;
258 doc_it->second.push_back(std::move(dt_uniq));
271 std::cerr <<
"InkscapeApplication::revert_document: Document never saved, cannot revert." << std::endl;
280 std::cerr <<
"InkscapeApplication::revert_document: Cannot open saved document!" << std::endl;
290 std::cerr <<
"InkscapeApplication::revert_document: Document not found!" << std::endl;
295 std::vector<SPDesktop *> desktops;
296 for (
auto const &
desktop : it->second) {
297 desktops.push_back(
desktop.get());
301 for (
auto const desktop : desktops) {
313 std::cerr <<
"InkscapeApplication::revert_document: Revert failed!" << std::endl;
328 std::cerr <<
"InkscapeApplication::close_document: No document!" << std::endl;
334 std::cerr <<
"InkscapeApplication::close_document: Document not registered with application." << std::endl;
338 if (!it->second.empty()) {
339 std::cerr <<
"InkscapeApplication::close_document: Window vector not empty!" << std::endl;
342 INKSCAPE.remove_document(it->first.get());
363 if (document->getRoot()->inkscape.getVersion().isInsideRangeInclusive({0, 1}, {0, 92})) {
380 std::vector<SPDocument *>
result;
383 result.push_back(doc.get());
397 std::cerr <<
"InkscapeApplication::window_open: Not in gui mode!" << std::endl;
401 auto const doc_it =
_documents.find(document);
403 std::cerr <<
"InkscapeApplication::window_open: Document not in map!" << std::endl;
407 auto const desktop = doc_it->second.emplace_back(std::make_unique<SPDesktop>(document->
getNamedView())).get();
413 auto const win =
_windows.emplace_back(std::make_unique<InkscapeWindow>(
desktop)).get();
435 std::cerr <<
"InkscapeApplication::close_window: No desktop!" << std::endl;
449 std::cerr <<
"InkscapeApplication::close_window: document not in map!" << std::endl;
453 auto dt_it = std::find_if(doc_it->second.begin(), doc_it->second.end(), [=] (
auto &dt) { return dt.get() == desktop; });
454 if (dt_it == doc_it->second.end()) {
455 std::cerr <<
"InkscapeApplication::close_window: desktop not found!" << std::endl;
468 INKSCAPE.remove_desktop(
desktop);
469 doc_it->second.erase(dt_it);
476 std::cerr <<
"InkscapeApplication::window_close_active: no active window!" << std::endl;
485 std::cout <<
"InkscapeApplication::dump()" << std::endl;
486 std::cout <<
" Documents: " <<
_documents.size() << std::endl;
487 for (
auto const &[doc, desktops] :
_documents) {
488 std::cout <<
" Document: " << (doc->getDocumentName() ? doc->getDocumentName() :
"unnamed") << std::endl;
489 for (
auto const &dt : desktops) {
490 std::cout <<
" Desktop: " << dt.get() << std::endl;
493 std::cout <<
" Windows: " <<
_windows.size() << std::endl;
495 std::cout <<
" Window: " << win->get_title() << std::endl;
496 for (
auto dt : win->get_desktop_widget()->get_desktops()) {
497 std::cout <<
" Desktop: " << dt << std::endl;
517 if (!isatty(fileno(stdout))) {
524 if (section_name.empty()) {
525 gapp->add_main_option_entry(Gio::Application::OptionType::BOOL, Glib::ustring(
"\b\b "));
527 gapp->add_main_option_entry(Gio::Application::OptionType::BOOL, Glib::ustring(
"\b\b \n") + section_name +
":");
534 std::cerr <<
"Multiple instances of InkscapeApplication" << std::endl;
539 using T = Gio::Application;
541 auto app_id = Glib::ustring(
"org.inkscape.Inkscape");
542 auto flags = Gio::Application::Flags::HANDLES_OPEN |
543 Gio::Application::Flags::CAN_OVERRIDE_APP_ID;
544 auto non_unique =
false;
550 if (Glib::getenv(
"INKSCAPE_APP_ID_TAG") !=
"") {
551 flags |= Gio::Application::Flags::CAN_OVERRIDE_APP_ID;
552 app_id +=
"." + Glib::getenv(
"INKSCAPE_APP_ID_TAG");
553 if (!Gio::Application::id_is_valid(app_id)) {
554 std::cerr <<
"InkscapeApplication: invalid application id: " << app_id.raw() << std::endl;
555 std::cerr <<
" tag must be ASCII and not start with a number." << std::endl;
558 }
else if (Glib::getenv(
"SELF_CALL") ==
"") {
561 auto test_app = Gio::Application::create(app_id, flags);
562 test_app->register_application();
563 if (test_app->get_default()->is_remote()) {
565 Glib::VariantBase hint;
574 test_app->run(0,
nullptr);
575 Gio::Application::unset_default();
578 if (gtk_init_check()) {
579 g_set_prgname(app_id.c_str());
594 gapp->signal_startup().connect([
this]() { this->
on_startup(); });
595 gapp->signal_activate().connect([
this]() { this->
on_activate(); });
634 gapp->set_option_context_parameter_string(_(
"file1 [file2 [fileN]]"));
635 gapp->set_option_context_summary(_(
"Process (or open) one or more files."));
636 gapp->set_option_context_description(Glib::ustring(
"\n") + _(
"Examples:") +
'\n'
637 +
" " + Glib::ustring::compose(_(
"Export input SVG (%1) to PDF (%2) format:"),
"in.svg",
"out.pdf") +
'\n'
638 +
'\t' +
"inkscape --export-filename=out.pdf in.svg\n"
639 +
" " + Glib::ustring::compose(_(
"Export input files (%1) to PNG format keeping original name (%2):"),
"in1.svg, in2.svg",
"in1.png, in2.png") +
'\n'
640 +
'\t' +
"inkscape --export-type=png in1.svg in2.svg\n"
641 +
" " + Glib::ustring::compose(_(
"See %1 and %2 for more details."),
"'man inkscape'",
"http://wiki.inkscape.org/wiki/index.php/Using_the_Command_Line"));
645 gapp->add_main_option_entry(T::OptionType::BOOL,
"version",
'V', N_(
"Print Inkscape version"),
"");
646 gapp->add_main_option_entry(T::OptionType::BOOL,
"debug-info",
'\0', N_(
"Print debugging information"),
"");
647 gapp->add_main_option_entry(T::OptionType::BOOL,
"system-data-directory",
'\0', N_(
"Print system data directory"),
"");
648 gapp->add_main_option_entry(T::OptionType::BOOL,
"user-data-directory",
'\0', N_(
"Print user data directory"),
"");
649 gapp->add_main_option_entry(T::OptionType::BOOL,
"list-input-types",
'\0', N_(
"List all available input file extensions"),
"");
650 gapp->add_main_option_entry(T::OptionType::STRING,
"app-id-tag",
'\0', N_(
"Create a unique instance of Inkscape with the application ID 'org.inkscape.Inkscape.TAG'"),
"");
654 gapp->add_main_option_entry(T::OptionType::BOOL,
"pipe",
'p', N_(
"Read input file from standard input (stdin)"),
"");
655 gapp->add_main_option_entry(T::OptionType::STRING,
"pages",
'n', N_(
"Page numbers to import from multi-page document, i.e. PDF"), N_(
"PAGE[,PAGE]"));
656 gapp->add_main_option_entry(T::OptionType::BOOL,
"pdf-poppler",
'\0', N_(
"Use poppler when importing via commandline"),
"");
657 gapp->add_main_option_entry(T::OptionType::STRING,
"pdf-font-strategy",
'\0', N_(
"How fonts are parsed in the internal PDF importer [draw-missing|draw-all|delete-missing|delete-all|substitute|keep]"), N_(
"STRATEGY"));
658 gapp->add_main_option_entry(T::OptionType::STRING,
"convert-dpi-method",
'\0', N_(
"Method used to convert pre-0.92 document dpi, if needed: [none|scale-viewbox|scale-document]"), N_(
"METHOD"));
659 gapp->add_main_option_entry(T::OptionType::BOOL,
"no-convert-text-baseline-spacing",
'\0', N_(
"Do not fix pre-0.92 document's text baseline spacing on opening"),
"");
663 gapp->add_main_option_entry(T::OptionType::FILENAME,
"export-filename",
'o', N_(
"Output file name (defaults to input filename; file type is guessed from extension if present; use '-' to write to stdout)"), N_(
"FILENAME"));
664 gapp->add_main_option_entry(T::OptionType::BOOL,
"export-overwrite",
'\0', N_(
"Overwrite input file (otherwise add '_out' suffix if type doesn't change)"),
"");
665 gapp->add_main_option_entry(T::OptionType::STRING,
"export-type",
'\0', N_(
"File type(s) to export: [svg,png,ps,eps,pdf,emf,wmf,xaml]"), N_(
"TYPE[,TYPE]*"));
666 gapp->add_main_option_entry(T::OptionType::STRING,
"export-extension",
'\0', N_(
"Extension ID to use for exporting"), N_(
"EXTENSION-ID"));
670 gapp->add_main_option_entry(T::OptionType::BOOL,
"export-area-page",
'C', N_(
"Area to export is page"),
"");
671 gapp->add_main_option_entry(T::OptionType::BOOL,
"export-area-drawing",
'D', N_(
"Area to export is whole drawing (ignoring page size)"),
"");
672 gapp->add_main_option_entry(T::OptionType::STRING,
"export-area",
'a', N_(
"Area to export in SVG user units"), N_(
"x0:y0:x1:y1"));
673 gapp->add_main_option_entry(T::OptionType::BOOL,
"export-area-snap",
'\0', N_(
"Snap the bitmap export area outwards to the nearest integer values"),
"");
674 gapp->add_main_option_entry(T::OptionType::DOUBLE,
"export-dpi",
'd', N_(
"Resolution for bitmaps and rasterized filters; default is 96"), N_(
"DPI"));
675 gapp->add_main_option_entry(T::OptionType::INT,
"export-width",
'w', N_(
"Bitmap width in pixels (overrides --export-dpi)"), N_(
"WIDTH"));
676 gapp->add_main_option_entry(T::OptionType::INT,
"export-height",
'h', N_(
"Bitmap height in pixels (overrides --export-dpi)"), N_(
"HEIGHT"));
677 gapp->add_main_option_entry(T::OptionType::INT,
"export-margin",
'\0', N_(
"Margin around export area: units of page size for SVG, mm for PS/PDF"), N_(
"MARGIN"));
681 gapp->add_main_option_entry(T::OptionType::STRING,
"export-page",
'\0', N_(
"Page number to export"), N_(
"all|n[,a-b]"));
682 gapp->add_main_option_entry(T::OptionType::STRING,
"export-id",
'i', N_(
"ID(s) of object(s) to export"), N_(
"OBJECT-ID[;OBJECT-ID]*"));
683 gapp->add_main_option_entry(T::OptionType::BOOL,
"export-id-only",
'j', N_(
"Hide all objects except object with ID selected by export-id"),
"");
684 gapp->add_main_option_entry(T::OptionType::BOOL,
"export-plain-svg",
'l', N_(
"Remove Inkscape-specific SVG attributes/properties"),
"");
685 gapp->add_main_option_entry(T::OptionType::INT,
"export-ps-level",
'\0', N_(
"Postscript level (2 or 3); default is 3"), N_(
"LEVEL"));
686 gapp->add_main_option_entry(T::OptionType::STRING,
"export-pdf-version",
'\0', N_(
"PDF version (1.4 or 1.5); default is 1.5"), N_(
"VERSION"));
687 gapp->add_main_option_entry(T::OptionType::BOOL,
"export-text-to-path",
'T', N_(
"Convert text to paths (PS/EPS/PDF/SVG)"),
"");
688 gapp->add_main_option_entry(T::OptionType::BOOL,
"export-latex",
'\0', N_(
"Export text separately to LaTeX file (PS/EPS/PDF)"),
"");
689 gapp->add_main_option_entry(T::OptionType::BOOL,
"export-ignore-filters",
'\0', N_(
"Render objects without filters instead of rasterizing (PS/EPS/PDF)"),
"");
690 gapp->add_main_option_entry(T::OptionType::BOOL,
"export-use-hints",
't', N_(
"Use stored filename and DPI hints when exporting object selected by --export-id"),
"");
691 gapp->add_main_option_entry(T::OptionType::STRING,
"export-background",
'b', N_(
"Background color for exported bitmaps (any SVG color string)"), N_(
"COLOR"));
693 gapp->add_main_option_entry(T::OptionType::STRING,
"export-background-opacity",
'y', N_(
"Background opacity for exported bitmaps (0.0 to 1.0, or 1 to 255)"), N_(
"VALUE"));
694 gapp->add_main_option_entry(T::OptionType::STRING,
"export-png-color-mode",
'\0', N_(
"Color mode (bit depth and color type) for exported bitmaps (Gray_1/Gray_2/Gray_4/Gray_8/Gray_16/RGB_8/RGB_16/GrayAlpha_8/GrayAlpha_16/RGBA_8/RGBA_16)"), N_(
"COLOR-MODE"));
695 gapp->add_main_option_entry(T::OptionType::STRING,
"export-png-use-dithering",
'\0', N_(
"Force dithering or disables it"),
"false|true");
697 gapp->add_main_option_entry(T::OptionType::STRING,
"export-png-compression",
'\0', N_(
"Compression level for PNG export (0 to 9); default is 6"), N_(
"LEVEL"));
699 gapp->add_main_option_entry(T::OptionType::STRING,
"export-png-antialias",
'\0', N_(
"Antialias level for PNG export (0 to 3); default is 2"), N_(
"LEVEL"));
700 gapp->add_main_option_entry(T::OptionType::BOOL,
"export-make-paths",
'\0', N_(
"Attempt to make the export directory if it doesn't exist."),
"");
704 gapp->add_main_option_entry(T::OptionType::STRING,
"query-id",
'I', N_(
"ID(s) of object(s) to be queried"), N_(
"OBJECT-ID[,OBJECT-ID]*"));
705 gapp->add_main_option_entry(T::OptionType::BOOL,
"query-all",
'S', N_(
"Print bounding boxes of all objects"),
"");
706 gapp->add_main_option_entry(T::OptionType::BOOL,
"query-x",
'X', N_(
"X coordinate of drawing or object (if specified by --query-id)"),
"");
707 gapp->add_main_option_entry(T::OptionType::BOOL,
"query-y",
'Y', N_(
"Y coordinate of drawing or object (if specified by --query-id)"),
"");
708 gapp->add_main_option_entry(T::OptionType::BOOL,
"query-width",
'W', N_(
"Width of drawing or object (if specified by --query-id)"),
"");
709 gapp->add_main_option_entry(T::OptionType::BOOL,
"query-height",
'H', N_(
"Height of drawing or object (if specified by --query-id)"),
"");
710 gapp->add_main_option_entry(T::OptionType::BOOL,
"query-pages",
'\0', N_(
"Number of pages in the opened file."),
"");
714 gapp->add_main_option_entry(T::OptionType::BOOL,
"vacuum-defs",
'\0', N_(
"Remove unused definitions from the <defs> section(s) of document"),
"");
715 gapp->add_main_option_entry(T::OptionType::STRING,
"select",
'\0', N_(
"Select objects: comma-separated list of IDs"), N_(
"OBJECT-ID[,OBJECT-ID]*"));
719 gapp->add_main_option_entry(T::OptionType::STRING,
"actions",
'a', N_(
"List of actions (with optional arguments) to execute"), N_(
"ACTION(:ARG)[;ACTION(:ARG)]*"));
720 gapp->add_main_option_entry(T::OptionType::BOOL,
"action-list",
'\0', N_(
"List all available actions"),
"");
721 gapp->add_main_option_entry(T::OptionType::FILENAME,
"actions-file",
'\0', N_(
"Use a file to input actions list"), N_(
"FILENAME"));
725 gapp->add_main_option_entry(T::OptionType::BOOL,
"with-gui",
'g', N_(
"With graphical user interface (required by some actions)"),
"");
726 gapp->add_main_option_entry(T::OptionType::BOOL,
"batch-process",
'\0', N_(
"Close GUI after executing all actions"),
"");
728 gapp->add_main_option_entry(T::OptionType::BOOL,
"shell",
'\0', N_(
"Start Inkscape in interactive shell mode"),
"");
729 gapp->add_main_option_entry(T::OptionType::BOOL,
"active-window",
'q', N_(
"Use active window from commandline"),
"");
738 gtk_app()->property_register_session() =
true;
753 g_assert_not_reached();
760 if (replace && old_document &&
desktop) {
766 if (it->second.empty()) {
784 g_assert_not_reached();
792 bool cancelled =
false;
798 auto recentmanager = Gtk::RecentManager::get_default();
799 recentmanager->add_item(file->get_uri());
802 bool replace = old_document && old_document->
getVirgin();
806 }
else if (!cancelled) {
807 std::cerr <<
"InkscapeApplication::create_window: Failed to load: "
808 << file->get_parse_name().raw() << std::endl;
810 gchar *text = g_strdup_printf(_(
"Failed to load the requested file %s"), file->get_parse_name().c_str());
820 std::cerr <<
"InkscapeApplication::create_window: Failed to open default document!" << std::endl;
835 g_assert_not_reached();
842 std::cerr <<
"InkscapeApplication::destroy_window: window has no document!" << std::endl;
850 if (it->second.size() == 1) {
866 for (
auto const &window :
gtk_app()->get_windows()) {
872 if (it->second.size() == 0) {
878 std::cerr <<
"InkscapeApplication::destroy_window: Could not find document!" << std::endl;
891 auto new_win =
_windows.emplace_back(std::make_unique<InkscapeWindow>(
desktop)).get();
898 g_assert_not_reached();
904 if (!desktops.empty()) {
959 _start_screen = std::make_unique<Inkscape::UI::Dialog::StartScreen>();
990 Gtk::Window::set_default_icon_name(
"org.inkscape.Inkscape");
1011 std::istreambuf_iterator<char> begin(std::cin),
end;
1012 std::string s(begin,
end);
1034 std::cerr <<
"InkscapeApplication::on_activate: failed to create document!" << std::endl;
1054 auto win_it = std::find_if(
_windows.begin(),
_windows.end(), [=] (
auto &
w) { return w.get() == window; });
1071 INKSCAPE.set_pages(
_pages);
1076 for (
auto &file : files) {
1077 std::cerr <<
" * input-filename: '" << file->get_path().c_str() <<
"'\n";
1079 std::cerr <<
"InkscapeApplication::on_open: "
1080 "Can't use '--export-filename' with multiple input files "
1081 "(output file would be overwritten for each input file). "
1082 "Please use '--export-type' instead and rename manually."
1087 for (
auto file : files) {
1093 std::cerr <<
"InkscapeApplication::on_open: failed to create document!" << std::endl;
1110 auto const re_colon = Glib::Regex::create(
"\\s*:\\s*");
1113 std::vector<Glib::ustring> tokens = Glib::Regex::split_simple(
"\\s*;\\s*", input);
1114 for (
auto token : tokens) {
1116 std::vector<Glib::ustring> tokens2 = re_colon->split(token, 0,
static_cast<Glib::Regex::MatchFlags
>(0), 2);
1117 Glib::ustring action;
1118 Glib::ustring value;
1119 if (tokens2.size() > 0) {
1120 action = tokens2[0];
1122 if (action.find_first_not_of(
" \f\n\r\t\v") == std::string::npos) {
1125 if (tokens2.size() > 1) {
1129 Glib::RefPtr<Gio::Action> action_ptr =
_gio_application->lookup_action(action);
1132 const GVariantType* gtype = g_action_get_parameter_type(action_ptr->gobj());
1135 Glib::VariantType type = action_ptr->get_parameter_type();
1136 if (type.get_string() ==
"b") {
1138 if (value ==
"1" || value ==
"true" || value.empty()) {
1140 }
else if (value ==
"0" || value ==
"false") {
1143 std::cerr <<
"InkscapeApplication::parse_actions: Invalid boolean value: " << action <<
":" << value << std::endl;
1145 action_vector.emplace_back(action, Glib::Variant<bool>::create(b));
1146 }
else if (type.get_string() ==
"i") {
1147 action_vector.emplace_back(action, Glib::Variant<int>::create(std::stoi(value)));
1148 }
else if (type.get_string() ==
"d") {
1149 action_vector.emplace_back(action, Glib::Variant<double>::create(std::stod(value)));
1150 }
else if (type.get_string() ==
"s") {
1151 action_vector.emplace_back(action, Glib::Variant<Glib::ustring>::create(value));
1152 }
else if (type.get_string() ==
"(dd)") {
1153 std::vector<Glib::ustring> tokens3 = Glib::Regex::split_simple(
",", value.c_str());
1154 if (tokens3.size() != 2) {
1155 std::cerr <<
"InkscapeApplication::parse_actions: " << action <<
" requires two comma separated numbers" << std::endl;
1162 d0 = std::stod(tokens3[0]);
1163 d1 = std::stod(tokens3[1]);
1165 std::cerr <<
"InkscapeApplication::parse_actions: " << action <<
" requires two comma separated numbers" << std::endl;
1169 action_vector.emplace_back(action, Glib::Variant<std::tuple<double, double>>
::create({d0, d1}));
1171 std::cerr <<
"InkscapeApplication::parse_actions: unhandled action value: "
1172 << action <<
": " << type.get_string() << std::endl;
1176 action_vector.emplace_back(action, Glib::VariantBase());
1179 std::cerr <<
"InkscapeApplication::parse_actions: could not find action for: " << action << std::endl;
1184#ifdef WITH_GNU_READLINE
1189 static std::vector<Glib::ustring> actions;
1192 if (actions.size() == 0) {
1194 actions = app->gio_app()->list_actions();
1195 std::sort(actions.begin(), actions.end());
1198 static int list_index = 0;
1206 const char*
name =
nullptr;
1207 while (list_index < actions.size()) {
1208 name = actions[list_index].c_str();
1210 if (strncmp (
name, text,
len) == 0) {
1211 return (strdup(
name));
1215 return ((
char*)
nullptr);
1220 char **matches = (
char**)
nullptr;
1233 rl_readline_name =
"inkscape";
1242 std::cout <<
"Inkscape interactive shell mode. Type 'action-list' to list all actions. "
1243 <<
"Type 'quit' to quit." << std::endl;
1244 std::cout <<
" Input of the form:" << std::endl;
1245 std::cout <<
" action1:arg1; action2:arg2; ..." << std::endl;
1247 std::cout <<
"Only actions that don't require a desktop may be used." << std::endl;
1250#ifdef WITH_GNU_READLINE
1254 gchar *locale_filename = g_win32_locale_filename_from_utf8(history_file.c_str());
1255 if (locale_filename) {
1256 history_file = locale_filename;
1257 g_free(locale_filename);
1261 static bool init =
false;
1267 int error = read_history(history_file.c_str());
1268 if (error && error != ENOENT) {
1269 std::cerr <<
"read_history error: " << std::strerror(error) <<
" " << history_file << std::endl;
1274 while (std::cin.good()) {
1278#ifdef WITH_GNU_READLINE
1279 char *readline_input = readline(
"> ");
1280 if (readline_input) {
1281 input = readline_input;
1282 if (input !=
"quit" && input !=
"q") {
1283 add_history(readline_input);
1288 free(readline_input);
1291 std::getline(std::cin, input);
1295 input = std::regex_replace(input, std::regex(
" +$"),
"");
1297 if (eof || input ==
"quit" || input ==
"q") {
1302 if (active_window) {
1303 input =
"active-window-start;" + input +
";active-window-end";
1308 if (active_window) {
1313 auto context = Glib::MainContext::get_default();
1314 while (context->iteration(
false)) {};
1318#ifdef WITH_GNU_READLINE
1319 stifle_history(200);
1320 int error = write_history(history_file.c_str());
1322 std::cerr <<
"write_history error: " << std::strerror(error) <<
" " << history_file << std::endl;
1337 if (Glib::file_test(tmpfile, Glib::FileTest::EXISTS)) {
1340 std::cerr <<
"couldn't process response. File not found" << std::endl;
1343 std::this_thread::sleep_for(std::chrono::milliseconds(10));
1348 unlink(tmpfile.c_str());
1351 auto awo = std::ifstream(tmpfile);
1353 std::cout <<
"couldn't process response. Couldn't read" << std::endl;
1357 auto const content = std::string(std::istreambuf_iterator<char>(awo), std::istreambuf_iterator<char>());
1360 auto doc =
sp_repr_read_mem(content.c_str(), strlen(content.c_str()),
nullptr);
1362 std::cout <<
"couldn't process response. Wrong data" << std::endl;
1372 auto grandchild =
child->firstChild();
1373 auto res = grandchild ? grandchild->content() :
nullptr;
1375 if (!g_strcmp0(
child->name(),
"cerr")) {
1376 std::cerr << res << std::endl;
1378 std::cout << res << std::endl;
1385 std::cout <<
"no output" << std::endl;
1404 std::cerr <<
"InkscapeApplication::on_handle_local_options: options is null!" << std::endl;
1409 if (options->contains(
"app-id-tag")) {
1410 Glib::ustring id_tag;
1411 options->lookup_value(
"app-id-tag", id_tag);
1412 Glib::ustring app_id =
"org.inkscape.Inkscape." + id_tag;
1413 if (Gio::Application::id_is_valid(app_id)) {
1416 std::cerr <<
"InkscapeApplication: invalid application id: " << app_id.raw() << std::endl;
1417 std::cerr <<
" tag must be ASCII and not start with a number." << std::endl;
1425 if (options->contains(
"version")) {
1427 return EXIT_SUCCESS;
1430 if (options->contains(
"debug-info")) {
1432 return EXIT_SUCCESS;
1435 if (options->contains(
"system-data-directory")) {
1437 return EXIT_SUCCESS;
1440 if (options->contains(
"user-data-directory")) {
1442 return EXIT_SUCCESS;
1452 auto base = Glib::VariantBase();
1458 if (options->contains(
"pipe") ||
1460 options->contains(
"export-filename") ||
1461 options->contains(
"export-overwrite") ||
1462 options->contains(
"export-type") ||
1463 options->contains(
"export-page") ||
1465 options->contains(
"export-area-page") ||
1466 options->contains(
"export-area-drawing") ||
1467 options->contains(
"export-area") ||
1468 options->contains(
"export-area-snap") ||
1469 options->contains(
"export-dpi") ||
1470 options->contains(
"export-width") ||
1471 options->contains(
"export-height") ||
1472 options->contains(
"export-margin") ||
1473 options->contains(
"export-height") ||
1475 options->contains(
"export-id") ||
1476 options->contains(
"export-id-only") ||
1477 options->contains(
"export-plain-svg") ||
1478 options->contains(
"export-ps-level") ||
1479 options->contains(
"export-pdf-version") ||
1480 options->contains(
"export-text-to_path") ||
1481 options->contains(
"export-latex") ||
1482 options->contains(
"export-ignore-filters") ||
1483 options->contains(
"export-use-hints") ||
1484 options->contains(
"export-background") ||
1485 options->contains(
"export-background-opacity") ||
1486 options->contains(
"export-text-to_path") ||
1487 options->contains(
"export-png-color-mode") ||
1488 options->contains(
"export-png-use-dithering") ||
1489 options->contains(
"export-png-compression") ||
1490 options->contains(
"export-png-antialias") ||
1491 options->contains(
"export-make-paths") ||
1493 options->contains(
"query-id") ||
1494 options->contains(
"query-x") ||
1495 options->contains(
"query-all") ||
1496 options->contains(
"query-y") ||
1497 options->contains(
"query-width") ||
1498 options->contains(
"query-height") ||
1499 options->contains(
"query-pages") ||
1501 options->contains(
"vacuum-defs") ||
1502 options->contains(
"select") ||
1503 options->contains(
"list-input-types") ||
1504 options->contains(
"action-list") ||
1505 options->contains(
"actions") ||
1506 options->contains(
"actions-file") ||
1507 options->contains(
"shell")
1512 if (options->contains(
"with-gui") ||
1513 options->contains(
"batch-process")
1517 std::cerr <<
"No GUI available, some actions may fail" << std::endl;
1521 if (options->contains(
"shell"))
_use_shell =
true;
1522 if (options->contains(
"pipe"))
_use_pipe =
true;
1525 if (options->contains(
"export-filename") ||
1526 options->contains(
"export-type") ||
1527 options->contains(
"export-overwrite") ||
1528 options->contains(
"export-use-hints")
1540 Glib::ustring app_id =
"org.inkscape.Inkscape.p" + std::to_string(getpid());
1547 Glib::ustring actions;
1548 if (options->contains(
"actions-file")) {
1549 std::string fileactions;
1550 options->lookup_value(
"actions-file", fileactions);
1551 if (!fileactions.empty()) {
1552 std::ifstream awo(fileactions);
1554 std::string content((std::istreambuf_iterator<char>(awo)), (std::istreambuf_iterator<char>()));
1558 }
else if (options->contains(
"actions")) {
1563 if (options->contains(
"action-list")) {
1567 if (options->contains(
"list-input-types")) {
1573 if (options->contains(
"pages")) {
1574 options->lookup_value(
"pages",
_pages);
1577 if (options->contains(
"pdf-poppler")) {
1581 if (options->contains(
"pdf-font-strategy")) {
1582 Glib::ustring strategy;
1583 options->lookup_value(
"pdf-font-strategy", strategy);
1585 if (strategy ==
"delete-all") {
1588 if (strategy ==
"delete-missing") {
1591 if (strategy ==
"draw-all") {
1594 if (strategy ==
"keep") {
1597 if (strategy ==
"substitute") {
1602 if (options->contains(
"convert-dpi-method")) {
1603 Glib::ustring method;
1604 options->lookup_value(
"convert-dpi-method", method);
1605 if (!method.empty()) {
1606 _command_line_actions.emplace_back(
"convert-dpi-method", Glib::Variant<Glib::ustring>::create(method));
1610 if (options->contains(
"no-convert-text-baseline-spacing")) {
1617 if (options->contains(
"query-id")) {
1618 Glib::ustring query_id;
1619 options->lookup_value(
"query-id", query_id);
1620 if (!query_id.empty()) {
1636 if (options->contains(
"select")) {
1637 Glib::ustring select;
1638 options->lookup_value(
"select", select);
1639 if (!select.empty()) {
1645 if (options->contains(
"export-filename")) {
1649 if (options->contains(
"export-type")) {
1652 if (options->contains(
"export-extension")) {
1659 if (options->contains(
"export-page")) {
1664 if (options->contains(
"export-area")) {
1665 Glib::ustring area{};
1666 options->lookup_value(
"export-area", area);
1670 if (options->contains(
"export-area-drawing")) {
1673 if (options->contains(
"export-area-page")) {
1677 if (options->contains(
"export-margin")) {
1683 if (options->contains(
"export-width")) {
1687 if (options->contains(
"export-height")) {
1692 if (options->contains(
"export-id")) {
1699 if (options->contains(
"export-dpi")) {
1706 if (options->contains(
"export-ps-level")) {
1710 if (options->contains(
"export-pdf-version")) {
1718 if (options->contains(
"export-background")) {
1723 if (options->contains(
"export-background-opacity")) {
1724 Glib::ustring opacity;
1725 options->lookup_value(
"export-background-opacity", opacity);
1729 if (options->contains(
"export-png-color-mode")) {
1733 if (options->contains(
"export-png-use-dithering")) {
1735 options->lookup_value(
"export-png-use-dithering", val);
1736 if (val ==
"true") {
1738#if CAIRO_VERSION < CAIRO_VERSION_ENCODE(1, 18, 0)
1739 std::cerr <<
"Your cairo version does not support dithering! Option will be ignored." << std::endl;
1743 else std::cerr <<
"invalid value for export-png-use-dithering. Ignoring." << std::endl;
1749 if (options->contains(
"export-png-compression")) {
1750 Glib::ustring compression;
1751 options->lookup_value(
"export-png-compression", compression);
1752 const char *begin = compression.raw().c_str();
1754 long ival = strtol(begin, &
end, 10);
1755 if (
end == begin || *
end !=
'\0' || errno == ERANGE) {
1756 std::cerr <<
"Cannot parse integer value "
1758 <<
" for --export-png-compression; the default value "
1769 if (options->contains(
"export-png-antialias")) {
1770 Glib::ustring antialias;
1771 options->lookup_value(
"export-png-antialias", antialias);
1772 const char *begin = antialias.raw().c_str();
1774 long ival = strtol(begin, &
end, 10);
1775 if (
end == begin || *
end !=
'\0' || errno == ERANGE) {
1776 std::cerr <<
"Cannot parse integer value "
1778 <<
" for --export-png-antialias; the default value "
1792 std::cerr <<
"Active window is not available on macOS" << std::endl;
1794 std::cerr <<
"No active desktop to run" << std::endl;
1796 return EXIT_SUCCESS;
1808 return EXIT_SUCCESS;
1810 GVariantDict *options_copy = options->gobj_copy();
1811 GVariant *options_var = g_variant_dict_end(options_copy);
1812 if (g_variant_get_size(options_var) != 0) {
1815 g_variant_dict_unref(options_copy);
1816 g_variant_unref(options_var);
1833 for (
auto window :
gtk_app()->get_windows()) {
1854 INKSCAPE.activate_desktop(
desktop);
1863 auto actions = gapp->list_actions();
1864 std::sort(actions.begin(), actions.end());
1865 for (
auto const &action : actions) {
1866 Glib::ustring fullname(
"app." + action);
1867 std::cout << std::left << std::setw(20) << action
1880 for (
auto *imod : extension_list) {
1881 auto suffix = imod->get_extension();
1882 if (suffix[0] ==
'.') {
1885 std::cout << suffix << std::endl;
1895 [&](
int sum,
auto& v){ return sum + static_cast<int>(v.second.size()); });
1918 transform(menu.begin(), menu.end(), menu.begin(), ::tolower);
1919 for (
auto &x:menu) {
1930 std::string aid = effect->get_sanitized_id();
1931 std::string action_id =
"app." + aid;
1935 auto action = gapp->add_action(aid, [effect](){
action_effect(effect,
true); });
1936 auto action_noprefs = gapp->add_action(aid +
".noprefs", [effect](){
action_effect(effect,
false); });
1941 if (effect->hidden_from_menu())
continue;
1944 auto sub_menu_list = effect->get_menu_list();
1947 auto description = effect->get_menu_tip();
1948 if (description.empty()) description = effect->get_name();
1950 if (effect->is_filter_effect()) {
1951 std::vector<std::vector<Glib::ustring>>raw_data_filter =
1952 {{ action_id, effect->get_name(),
"Filters", description },
1953 { action_id +
".noprefs", Glib::ustring(effect->get_name()) +
" " + _(
"(No preferences)"),
"Filters (no prefs)", description }};
1954 app->get_action_extra_data().add_data(raw_data_filter);
1957 {{ action_id, effect->get_name(),
"Extensions", description },
1958 { action_id +
".noprefs", Glib::ustring(effect->get_name()) +
" " + _(
"(No preferences)"),
"Extensions (no prefs)", description }};
1963 std::cout <<
" Effect: name: " << effect->get_name();
1964 std::cout <<
" id: " << aid.c_str();
1965 std::cout <<
" menu: ";
1966 for (
auto sub_menu : sub_menu_list) {
1967 std::cout <<
"|" << sub_menu.raw();
1969 std::cout <<
"| icon: " << effect->find_icon_file();
1970 std::cout << std::endl;
1974 gchar *ellipsized_name = effect->takes_input() ? g_strdup_printf(_(
"%s..."), effect->get_name()) :
nullptr;
1975 Glib::ustring menu_name = ellipsized_name ? ellipsized_name : effect->get_name();
1976 bool is_filter = effect->is_filter_effect();
1977 app->get_action_effect_data().add_data(aid, is_filter, sub_menu_list, menu_name);
1978 g_free(ellipsized_name);
void add_actions_base(InkscapeApplication *app)
void add_actions_edit(InkscapeApplication *app)
Authors: Sushant A A sushant.co19@gmail.com
void add_actions_effect(InkscapeApplication *app)
std::vector< std::vector< Glib::ustring > > raw_data_effect
Authors: Sushant A A sushant.co19@gmail.com
void add_actions_element_a(InkscapeApplication *app)
void add_actions_element_image(InkscapeApplication *app)
void add_actions_file(InkscapeApplication *app)
void activate_any_actions(action_vector_t const &actions, Glib::RefPtr< Gio::Application > app, InkscapeWindow *win, SPDocument *doc)
This activates all actions, which are called even if you don't know or care about which action group ...
static bool use_active_window
std::string get_active_desktop_commands_location()
void add_actions_hide_lock(InkscapeApplication *app)
Authors: Sushant A A sushant.co19@gmail.com
void add_actions_object_align(InkscapeApplication *app)
void add_actions_object(InkscapeApplication *app)
void add_actions_output(InkscapeApplication *app)
void add_actions_path(InkscapeApplication *app)
void add_actions_selection_object(InkscapeApplication *app)
Authors: Sushant A A sushant.co19@gmail.com
void add_actions_selection(InkscapeApplication *app)
void add_actions_text(InkscapeApplication *app)
Authors: Sushant A A sushant.co19@gmail.com
void add_actions_tutorial(InkscapeApplication *app)
Authors: Sushant A A sushant.co19@gmail.com
void add_actions_window(InkscapeApplication *app)
Two-dimensional point that doubles as a vector.
void set_export_area(const Glib::ustring &area)
void set_export_area_type(ExportAreaType type)
Glib::ustring export_pdf_level
Glib::ustring export_page
bool export_png_use_dithering
Glib::ustring export_type
double export_background_opacity
Glib::ustring export_png_color_mode
void do_export(SPDocument *doc, std::string filename_in="")
int export_png_compression
Glib::ustring export_background
std::string export_filename
Glib::ustring export_extension
bool export_ignore_filters
void on_open(const Gio::Application::type_vec_files &files, const Glib::ustring &hint)
void desktopCloseActive()
SPDesktop * _active_desktop
void set_active_desktop(SPDesktop *desktop)
void document_fix(SPDesktop *desktop)
Fix up a document if necessary (Only fixes that require GUI).
std::vector< Glib::RefPtr< Gio::SimpleAction > > _effect_actions
void process_document(SPDocument *document, std::string output_path)
Common processing for documents.
void dump()
Debug function.
bool destroyDesktop(SPDesktop *desktop, bool keep_alive=false)
Destroy a window and close the document it contains.
bool document_swap(SPDesktop *desktop, SPDocument *document)
Swap out one document for another in a tab.
InkFileExportCmd _file_export
std::pair< SPDocument *, bool > document_open(Glib::RefPtr< Gio::File > const &file)
void _start_main_option_section(const Glib::ustring §ion_name="")
Gio::Application * gio_app()
The Gio application instance, never NULL.
std::unique_ptr< Inkscape::UI::Dialog::StartScreen > _start_screen
void shell(bool active_window=false)
bool document_revert(SPDocument *document)
Revert document: open saved document and swap it for each window.
SPDesktop * get_active_desktop()
Glib::RefPtr< Gio::Application > _gio_application
Glib::ustring _command_line_actions_input
std::map< std::unique_ptr< SPDocument >, std::vector< std::unique_ptr< SPDesktop > >, TransparentPtrLess< SPDocument > > _documents
void windowClose(InkscapeWindow *window)
SPDocument * get_active_document()
void init_extension_action_data()
SPDesktop * desktopOpen(SPDocument *document)
SPDocument * document_new(std::string const &template_filename={})
InkActionExtraData _action_extra_data
void parse_actions(const Glib::ustring &input, action_vector_t &action_vector)
static InkscapeApplication * instance()
Singleton instance.
bool _use_command_line_argument
int on_handle_local_options(const Glib::RefPtr< Glib::VariantDict > &options)
FontStrategy _pdf_font_strategy
Gtk::Application * gtk_app()
The Gtk application instance, or NULL if running headless without display.
void print_input_type_list() const
Prints file type extensions (without leading dot) of input formats.
InkscapeApplication()
Exclusively for the creation of the singleton instance inside main().
Inkscape::Selection * _active_selection
void detachDesktopToNewWindow(SPDesktop *desktop)
void create_window(Glib::RefPtr< Gio::File > const &file={})
Create a window given a Gio::File.
SPDocument * document_add(std::unique_ptr< SPDocument > document)
std::vector< std::unique_ptr< InkscapeWindow > > _windows
SPDocument * _active_document
void document_close(SPDocument *document)
Close a document, remove from app.
std::vector< SPDocument * > get_documents()
Get a list of open documents (from document map).
SPDesktop * createDesktop(SPDocument *document, bool replace)
Create a desktop given a document.
int get_number_of_windows() const
Return number of open Inkscape Windows (irrespective of number of documents)
action_vector_t _command_line_actions
void desktopClose(SPDesktop *desktop)
InkscapeWindow * _active_window
SPDesktopWidget * get_desktop_widget()
static void create(bool use_gui)
Creates a new Inkscape::Application global object.
void init(InkscapeApplication *app)
static AutoSave & getInstance()
std::vector< Effect * > get_effect_list()
Creates a list of all the Effect extensions.
std::list< Input * > InputList
InputList & get_input_list(InputList &ou_list)
Creates a list of all the Input extensions.
Effects are extensions that take a document and do something to it in place.
void effect(SPDesktop *desktop, SPDocument *document=nullptr)
The function that 'does' the effect itself.
bool prefs(SPDesktop *desktop)
bool _workingDialog
Whether a working dialog should be shown.
static Preferences * get()
Access the singleton Preferences object.
static DialogManager & singleton()
void save_dialogs_state(DialogContainer *docking_container)
static int get_start_mode()
Get the preference for the startup mode.
To do: update description of desktop.
double current_zoom() const
Geom::Point current_center() const
SPDocument * getDocument() const
InkscapeWindow const * getInkscapeWindow() const
void showInfoDialog(Glib::ustring const &message)
SPDesktopWidget * getDesktopWidget() const
void change_document(SPDocument *document)
Make desktop switch documents.
Inkscape::Selection * getSelection() const
void zoom_absolute(Geom::Point const &c, double zoom, bool keep_point=true)
Zoom to the given absolute zoom level.
Typed SVG document implementation.
Inkscape::Selection * getSelection()
char const * getDocumentFilename() const
void setVirgin(bool Virgin)
int ensureUpToDate(unsigned int object_modified_tag=0)
Repeatedly works on getting the document updated, since sometimes it takes more than one pass to get ...
SPNamedView * getNamedView()
Get the namedview for this document, creates it if it's not found.
Editable view implementation.
bool document_check_for_data_loss(SPDesktop *desktop)
Check if closing document associated with window will cause data loss, and if so opens a dialog that ...
void sp_file_fix_lpe(SPDocument *doc)
void sp_file_convert_dpi(SPDocument *doc)
helper functions for gettext
char ** readline_completion(const char *text, int start, int end)
std::string action_menu_name(std::string menu)
char * readline_generator(const char *text, int state)
void action_effect(Inkscape::Extension::Effect *effect, bool show_prefs)
Adds effect to Gio::Actions.
static InkscapeApplication * _instance
std::vector< std::pair< std::string, Glib::VariantBase > > action_vector_t
Consolidates version info for Inkscape, its various dependencies and the OS we're running on.
Inkscape - An SVG editor.
void sp_ui_error_dialog(char const *message)
std::unique_ptr< SPDocument > ink_file_open(std::span< char const > buffer)
Open a document from memory.
std::unique_ptr< SPDocument > ink_file_new(std::string const &Template)
Create a blank document, remove any template data.
DB db
This is the actual database object.
void init()
Invokes the init routines for internal modules.
static R & release(R &r)
Decrements the reference count of a anchored object.
std::string get_filename(Type type, char const *filename, bool localized, bool silent)
std::string profile_path()
std::string find_original_file(Glib::StdStringView const filepath, Glib::StdStringView const name)
Takes an absolute file path and returns a second file at the same directory location,...
void checkFontSubstitutions(SPDocument *doc)
int dialog_run(Gtk::Dialog &dialog)
This is a GTK4 porting aid meant to replace the removal of the Gtk::Dialog synchronous API.
std::string inkscape_revision()
Return Inkscape repository revision string.
bool fixBrokenLinks(SPDocument *doc)
std::string debug_info()
Return full debug info.
std::string inkscape_version()
Return Inkscape version string.
void initialize_gettext()
does all required gettext initialization and takes care of the respective locale directory paths
char const * get_inkscape_datadir()
Determine the location of the Inkscape data directory (typically the share/ folder from where Inkscap...
TODO: insert short description here.
Document * sp_repr_read_mem(const gchar *buffer, gint length, const gchar *default_ns)
Reads and parses XML from a buffer, returning it as an Document.
Inkscape::IO::Resource - simple resource API.
double sum(const double alpha[16], const double &x, const double &y)
void sp_namedview_window_from_document(SPDesktop *desktop)
SPRoot: SVG <svg> implementation.
A dialog for the start screen.
void init(int argc, char **argv, Toy *t, int width=600, int height=600)