Commit 408cb49b authored by Tavmjong Bah's avatar Tavmjong Bah Committed by Alex Valavanis

Rewrite of main.cpp using InkscapeApplication (Gtk::Application)

Use Gio::File for accessing files.
Use Gio options to handle command line arguments.
Use Gio::Actions for some command line arguments.
Move file export code to src/io/file-export-cmd.h/.cpp. Make into class.
parent f1b21219
# List of source files containing translatable strings.
# Please keep this file sorted alphabetically.
# Generated by ./generate_POTFILES.sh at Mon Nov 5 10:33:09 CET 2018
# Generated by ./generate_POTFILES.sh at Mon Nov 12 21:20:36 CET 2018
[encoding: UTF-8]
inkscape.appdata.xml.in
inkscape.desktop.in
......@@ -109,6 +109,7 @@ src/gradient-chemistry.cpp
src/gradient-drag.cpp
src/helper/gettext.cpp
src/helper/gettext.h
src/inkscape-application.cpp
src/inkscape.cpp
src/inkview-application.cpp
src/io/resource-manager.cpp
......@@ -178,7 +179,6 @@ src/live_effects/parameter/unit.cpp
src/live_effects/parameter/vector.cpp
src/main-cmdlineact.cpp
src/main-cmdlinexact.cpp
src/main.cpp
src/menus-skeleton.h
src/object/box3d.cpp
src/object/color-profile.cpp
......
......@@ -245,6 +245,7 @@ list(APPEND inkscape_SRC
# All folders for internal inkscape
# these call add_inkscape_source
add_subdirectory(actions)
add_subdirectory(debug)
add_subdirectory(display)
add_subdirectory(extension)
......@@ -278,7 +279,13 @@ set(inkscape_SRC
# -----------------------------------------------------------------------------
# Setup the executable
# -----------------------------------------------------------------------------
set(main_SRC main.cpp)
set(main_SRC
inkscape-main.cpp
inkscape-application.h
inkscape-application.cpp
actions/actions-base.h
actions/actions-base.cpp
)
set(view_SRC
inkview-main.cpp
inkview-application.h
......
# SPDX-License-Identifier: GPL-2.0-or-later
set(actions_SRC
# actions-base.cpp
# HEADERS
# actions-base.h
)
add_inkscape_source("${actions_SRC}")
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Gio::Actions tied to the application and independent of GUI.
*
* Copyright (C) 2018 Tavmjong Bah
*
* The contents of this file may be used under the GNU General Public License Version 2 or later.
*
*/
#include <iostream>
#include <giomm.h> // Not <gtkmm.h>! To eventually allow a headless version!
#include "actions-base.h"
#include "inkscape-application.h"
#include "inkscape.h" // Inkscape::Application
#include "inkscape-version.h" // Inkscape version
#include "path-prefix.h" // Extension directory
#include "extension/init.h" // List verbs
#include "verbs.h" // List verbs
#include "selection.h" // Selection
#include "object/sp-root.h" // query_all()
#include "file.h" // dpi convert method
void
print_inkscape_version()
{
std::cout << "Inkscape " << Inkscape::version_string << std::endl;
}
void
print_extension_directory()
{
std::cout << INKSCAPE_EXTENSIONDIR << std::endl;
}
void
print_verb_list()
{
// This really shouldn't go here, we should init the app.
// But, since we're just exiting in this path, there is
// no harm, and this is really a better place to put
// everything else.
Inkscape::Extension::init(); // extension/init.h
Inkscape::Verb::list(); // verbs.h
}
// Helper function: returns true if both document and selection found.
bool
get_document_and_selection(InkscapeApplication* app, SPDocument** document, Inkscape::Selection** selection)
{
*document = app->get_active_document();
if (!(*document)) {
std::cerr << "get_document_and_selection: No document!" << std::endl;
return false;
}
Inkscape::ActionContext context = INKSCAPE.action_context_for_document(*document);
*selection = context.getSelection();
if (!*selection) {
std::cerr << "get_document_and_selection: No selection!" << std::endl;
return false;
}
return true;
}
void
select_via_id(Glib::ustring ids, InkscapeApplication* app)
{
SPDocument* document = nullptr;
Inkscape::Selection* selection = nullptr;
if (!get_document_and_selection(app, &document, &selection)) {
return;
}
auto tokens = Glib::Regex::split_simple("\\s*,\\s*", ids);
for (auto id : tokens) {
SPObject* object = document->getObjectById(id);
if (object) {
selection->add(object);
} else {
std::cerr << "select: did not find object with id: " << id << std::endl;
}
}
}
// Helper function for query_x(), query_y(), query_width(), and query_height().
void
query_dimension(InkscapeApplication* app, bool extent, Geom::Dim2 const axis)
{
SPDocument* document = nullptr;
Inkscape::Selection* selection = nullptr;
if (!get_document_and_selection(app, &document, &selection)) {
return;
}
if (selection->isEmpty()) {
selection->add(document->getRoot());
}
bool first = true;
auto items = selection->items();
for (auto item : items) {
if (!first) {
std::cout << ",";
}
first = false;
Geom::OptRect area = item->documentVisualBounds();
if (area) {
if (extent) {
std::cout << area->dimensions()[axis];
} else {
std::cout << area->min()[axis];
}
} else {
std::cout << "0";
}
}
std::cout << std::endl;
}
void
query_x(InkscapeApplication* app)
{
query_dimension(app, false, Geom::X);
}
void
query_y(InkscapeApplication* app)
{
query_dimension(app, false, Geom::Y);
}
void
query_width(InkscapeApplication* app)
{
query_dimension(app, true, Geom::X);
}
void
query_height(InkscapeApplication* app)
{
query_dimension(app, true, Geom::Y);
}
// Helper for query_all()
void
query_all_recurse (SPObject *o)
{
SPItem *item = dynamic_cast<SPItem*>(o);
if (item && item->getId()) {
Geom::OptRect area = item->documentVisualBounds();
if (area) {
std::cout << item->getId() << ","
<< area->min()[Geom::X] << ","
<< area->min()[Geom::Y] << ","
<< area->dimensions()[Geom::X] << ","
<< area->dimensions()[Geom::Y] << std::endl;
}
for (auto& child: o->children) {
query_all_recurse (&child);
}
}
}
void
query_all(InkscapeApplication* app)
{
SPDocument* doc = app->get_active_document();
if (!doc) {
std::cerr << "query_all: no document!" << std::endl;
return;
}
SPObject *o = doc->getRoot();
if (o) {
query_all_recurse(o);
}
}
void
pdf_page(int page)
{
INKSCAPE.set_pdf_page(page);
}
void
convert_dpi_method(Glib::ustring method)
{
if (method == "none") {
sp_file_convert_dpi_method_commandline = FILE_DPI_UNCHANGED;
} else if (method == "scale-viewbox") {
sp_file_convert_dpi_method_commandline = FILE_DPI_VIEWBOX_SCALED;
} else if (method == "scale-document") {
sp_file_convert_dpi_method_commandline = FILE_DPI_DOCUMENT_SCALED;
} else {
std::cerr << "dpi_convert_method: invalid option" << std::endl;
}
}
void
no_convert_baseline()
{
sp_no_convert_text_baseline_spacing = true;
}
// Temporary: Verbs are to be replaced by Gio::Actions!
void
verbs(Glib::ustring verblist, InkscapeApplication* app)
{
auto tokens = Glib::Regex::split_simple("\\s*,\\s*", verblist);
for (auto token : tokens) {
std::vector<Glib::ustring> parts = Glib::Regex::split_simple("\\s*:\\s*", token); // Second part is always ignored... we could implement it but better to switch to Gio::Actions
if (!parts[0].empty()) {
Inkscape::Verb* verb = Inkscape::Verb::getbyid(parts[0].c_str());
if (verb == nullptr) {
std::cerr << "verbs_action: Invalid verb: " << parts[0] << std::endl;
break;
}
// Inkscape::ActionContext context = INKSCAPE.action_context_for_document(*document);
SPAction* action = verb->get_action(INKSCAPE.active_action_context());
sp_action_perform(action, nullptr); // Data is ignored!
}
}
}
void
vacuum_defs(InkscapeApplication* app)
{
SPDocument* document = nullptr;
Inkscape::Selection* selection = nullptr;
if (!get_document_and_selection(app, &document, &selection)) {
return;
}
document->vacuumDocument();
}
void
add_actions_base(InkscapeApplication* app)
{
// Note: "radio" actions are just an easy way to set type without using templating.
app->add_action("inkscape-version", sigc::ptr_fun(&print_inkscape_version ));
app->add_action("extension-directory", sigc::ptr_fun(&print_extension_directory));
app->add_action("verb-list", sigc::ptr_fun(&print_verb_list ));
app->add_action_radio_integer( "open-page", sigc::ptr_fun(&pdf_page), 0);
app->add_action_radio_string( "convert-dpi-method", sigc::ptr_fun(&convert_dpi_method), "none");
app->add_action( "no-convert-baseline", sigc::ptr_fun(&no_convert_baseline) );
app->add_action( "vacuum-defs", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&vacuum_defs), app) );
app->add_action_radio_string( "select", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&select_via_id), app), "null");
app->add_action_radio_string( "verb", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&verbs), app), "null");
app->add_action_radio_string( "query-id", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&select_via_id), app), "null"); // For backwards compatibility.
app->add_action( "query-x", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&query_x), app) );
app->add_action( "query-y", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&query_y), app) );
app->add_action( "query-width", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&query_width), app) );
app->add_action( "query-height", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&query_height), app) );
app->add_action( "query-all", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&query_all), app) );
}
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Gio::Actions tied to the application and without GUI.
*
* Copyright (C) 2018 Tavmjong Bah
*
* The contents of this file may be used under the GNU General Public License Version 2 or later.
*
*/
#ifndef INK_ACTIONS_BASE_H
#define INK_ACTIONS_BASE_H
class InkscapeApplication;
void add_actions_base(InkscapeApplication* app);
#endif // INK_ACTIONS_BASE_H
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* The main Inkscape application.
*
* Copyright (C) 2018 Tavmjong Bah
*
* The contents of this file may be used under the GNU General Public License Version 2 or later.
*
*/
#ifndef INKSCAPE_APPLICATION_H
#define INKSCAPE_APPLICATION_H
/*
* The main Inkscape application.
*
* Copyright (C) 2018 Tavmjong Bah
*
* The contents of this file may be used under the GNU General Public License Version 2 or later.
*
*/
#include <gtkmm.h>
#include "document.h"
#include "helper/action.h"
#include "io/file-export-cmd.h" // File export (non-verb)
class InkscapeApplication : public Gtk::Application
{
protected:
InkscapeApplication();
public:
static Glib::RefPtr<InkscapeApplication> create();
SPDocument* get_active_document();
protected:
void on_startup() override;
void on_startup2();
void on_activate() override;
void on_open(const Gio::Application::type_vec_files& files, const Glib::ustring& hint) override;
private:
void create_window(const Glib::RefPtr<Gio::File>& file = Glib::RefPtr<Gio::File>());
private:
// Callbacks
int on_handle_local_options(const Glib::RefPtr<Glib::VariantDict>& options);
// Actions
void on_new();
void on_quit();
void on_about();
Glib::RefPtr<Gtk::Builder> _builder;
bool _with_gui;
InkFileExportCmd _file_export;
// Documents are owned by the application which is responsible for opening/saving/exporting. WIP
std::vector<SPDocument*> _documents;
// Actions from the command line or file.
std::vector<std::pair<std::string, Glib::VariantBase> > _command_line_actions;
};
#endif // INKSCAPE_APPLICATION_H
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Inkscape - an ambitious vector drawing program
*
* Authors:
* Tavmjong Bah
*
* (C) 2018 Tavmjong Bah
*
* Released under GNU GPL v2+, read the file 'COPYING' for more information.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "inkscape-application.h"
int main(int argc, char *argv[])
{
auto application = InkscapeApplication::create();
return application->run(argc, argv);
}
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
......@@ -67,7 +67,7 @@
Inkscape::Application * Inkscape::Application::_S_inst = nullptr;
bool Inkscape::Application::_crashIsHappening = false;
#define DESKTOP_IS_ACTIVE(d) (!INKSCAPE._desktops->empty() && ((d) == INKSCAPE._desktops->front()))
#define DESKTOP_IS_ACTIVE(d) (INKSCAPE._desktops != nullptr && !INKSCAPE._desktops->empty() && ((d) == INKSCAPE._desktops->front()))
static void (* segv_handler) (int) = SIG_DFL;
static void (* abrt_handler) (int) = SIG_DFL;
......@@ -609,7 +609,7 @@ Application::~Application()
_S_inst = nullptr; // this will probably break things
refCount = 0;
gtk_main_quit ();
// gtk_main_quit ();
}
/** Sets the keyboard modifer to map to Alt.
......@@ -1279,6 +1279,7 @@ Application::action_context_for_document(SPDocument *doc)
// Document is not associated with any desktops - maybe we're in command-line mode
std::map<SPDocument *, AppSelectionModel *>::iterator sel_iter = _selection_models.find(doc);
if (sel_iter == _selection_models.end()) {
std::cout << "Application::action_context_for_document: no selection model" << std::endl;
return Inkscape::ActionContext();
}
return Inkscape::ActionContext(sel_iter->second->getSelection());
......@@ -1309,7 +1310,7 @@ Application::exit ()
signal_shut_down.emit();
Inkscape::Preferences::unload();
gtk_main_quit ();
//gtk_main_quit ();
}
......
......@@ -2,6 +2,8 @@
set(io_SRC
dir-util.cpp
file.cpp
file-export-cmd.cpp
resource.cpp
resource-manager.cpp
stream/bufferstream.cpp
......@@ -16,6 +18,8 @@ set(io_SRC
# -------
# Headers
dir-util.h
file.h
file-export-cmd.h
resource.h
resource-manager.h
stream/bufferstream.h
......
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* File export from the command line. This code use to be in main.cpp. It should be
* replaced by shared code (Gio::Actions?) for export from the file dialog.
*
* Copyright (C) 2018 Tavmjong Bah
*
* The contents of this file may be used under the GNU General Public License Version 2 or later.
*
*/
#ifndef INK_FILE_EXPORT_CMD_H
#define INK_FILE_EXPORT_CMD_H
#include <iostream>
#include <gtkmm.h>
class SPDocument;
class InkFileExportCmd {
public:
InkFileExportCmd();
void do_export(SPDocument* doc, std::string filename_in="");
private:
std::string get_filename_out(std::string filename_in="");
int do_export_svg( SPDocument* doc, std::string filename_out);
int do_export_png( SPDocument* doc, std::string filename_out);
int do_export_ps_pdf(SPDocument* doc, std::string filename_out, std::string mime_type);
int do_export_win_metafile(SPDocument* doc, std::string filename_out, std::string mime_type);
public:
// Should be private, but this is just temporary code (I hope!).
bool over_write;
// One-to-one correspondence with command line options
std::string export_filename; // Only if one file is processed!
Glib::ustring export_type;
bool export_overwrite;
Glib::ustring export_area;
bool export_area_drawing;
bool export_area_page;
int export_margin;
bool export_area_snap;
int export_width;
int export_height;
int export_dpi;
bool export_ignore_filters;
bool export_text_to_path;
int export_ps_level;
Glib::ustring export_pdf_level;
bool export_latex;
Glib::ustring export_id;
bool export_id_only;
bool export_use_hints;
Glib::ustring export_background;
double export_background_opacity;
bool export_plain_svg;
};
#endif // INK_FILE_EXPORT_CMD_H
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* File operations (independent of GUI)
*
* Copyright (C) 2018 Tavmjong Bah
*
* The contents of this file may be used under the GNU General Public License Version 2 or later.
*
*/
#include <iostream>
#include <gtkmm.h>
#include "file.h"
#include "document.h"
#include "extension/system.h" // Extension::open()
#include "extension/extension.h"
#include "extension/db.h"
#include "extension/output.h"
#include "extension/input.h"
// SPDocument*
// ink_file_new(const std::string &Template)
// {
// SPDocument *doc = SPDocument::createNewDoc( Template, true, true );
// return doc;
// }
SPDocument*
ink_file_open(const Glib::RefPtr<Gio::File>& file)
{
SPDocument *doc = nullptr;
std::string path = file->get_path();
try {
doc = Inkscape::Extension::open(nullptr, path.c_str());
} catch (Inkscape::Extension::Input::no_extension_found &e) {
doc = nullptr;
} catch (Inkscape::Extension::Input::open_failed &e) {
doc = nullptr;
}
// Try to open explicitly as SVG.
if (doc == nullptr) {
try {
doc = Inkscape::Extension::open(Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), path.c_str());
} catch (Inkscape::Extension::Input::no_extension_found &e) {
doc = nullptr;
} catch (Inkscape::Extension::Input::open_failed &e) {
doc = nullptr;
}
}
if (doc == nullptr) {
std::cerr << "ink_file_open: '" << path << "' cannot be opened!" << std::endl;
}
return doc;
}
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* File operations (independent of GUI)
*
* Copyright (C) 2018 Tavmjong Bah
*
* The contents of this file may be used under the GNU General Public License Version 2 or later.
*
*/
#ifndef INK_FILE_IO_H
#define INK_FILE_IO_H
class SPDocument;
//SPDocument* ink_file_new(const std::string &template = nullptr);
SPDocument* ink_file_open(const Glib::RefPtr<Gio::File>& file = Glib::RefPtr<Gio::File>());
// To do:
// ink_file_save()
// ink_file_export()
// ink_file_import()
#endif // INK_FILE_IO_H
This diff is collapsed.
  • mentioned in commit 6675a6fa

    Toggle commit list
  • I'm not sure if it was intended to be supported, but I guess it would be convenient to allow export to multiple files / formats at the same time:

    inkscape in.svg --export-file="out1.png" --export-file="out2.pdf"

    (currently only the last -export command seems to be honored).

    Similarly it might be nice to support

    inkscape in.svg --export-type="png,pdf"

    (i.e. a list of file types to export to)

  • I think that would be good too... but I've got some other things to fix first. Currently I'm reworking the do_export_png() function. It is obvious that multiple people contributed to the code at various points in time making it quite spaghetti like (like lot's of Inkscape's code...).

    Oh, only one instance of each option is allowed so it would have to be --export-file="out1.png,out2.png"

    Edited by Tavmjong Bah
  • Sure, take your time. I know what you mean, also it seems we duplicate a lot of code for every do_export_* function making some options work inconsistent (or not at all) for some formats.

    Hmm, to bad we can't add multiple switches, but I guess --export-file="out1.png,out2.png" could work just as well (and would be consistent with my suggestion for --export-type="png,pdf", where I already used a list.

  • I also noticed the duplicate code and inconsistency of options. I think the solution is to remove all options that apply to the document itself from the export functions and moving them to a common "document preparation" function. So, for example, setting the area of the export would be handles by the preparation function (probably by temporary changing the document size) while handling the PS Level would be handled by the PS export function.

  • @ede123 I don't have a good answer for your command line output questions. I started a wiki page for discussions: Console Output

  • OK, thanks.

    You might also want to include "g_print/g_printerr" in the list (as those are the actual counterparts to "std::cout/std::cerr") whereas the logging functions are actually a separate class of output functions that also behave slightly differently (i.e. can be redirected/formatted by use of a log handler, can be selectively enabled/disabled by the user by use of "G_MESSAGES_DEBUG" environment variable, etc.).

    Personally I think we should stick to the glib message output and debugging functions for warnings/error messages/etc. because of the added value of the log handler.

    For actual informational program output that is not considered "debug output" we should likely decide between plain C++ string streams (std::cout/std::cerr) and g_print/g_printerr. It seems questionable the glibmm equivalents (Gio::ApplicationCommandLine::print/Gio::ApplicationCommandLine::printerr) would be adopted.

  • Is it normal that everything now needs a graphical server ? I was trying to make export png work (to fix the tests…), but even --version or --help do not work now (unable to init server / cannot open display)

    Edited by Marc Jeanmougin
  • No, you should not need a graphical server when using the command-line export arguments (or --version).

  • mentioned in issue #60 (closed)

    Toggle commit list
  • mentioned in commit 67791edc

    Toggle commit list
  • mentioned in commit Qantas94Heavy/inkscape@5344d529

    Toggle commit list
  • mentioned in merge request !594 (merged)

    Toggle commit list
  • mentioned in commit Qantas94Heavy/inkscape@ddbfad80

    Toggle commit list
  • mentioned in merge request !729 (merged)

    Toggle commit list
  • mentioned in merge request !730 (merged)

    Toggle commit list
  • mentioned in commit 96c7da47

    Toggle commit list
  • mentioned in issue inbox#564

    Toggle commit list
  • mentioned in commit 8a172e97

    Toggle commit list
  • mentioned in commit 22b30cec

    Toggle commit list