22#include <boost/stacktrace.hpp>
25#include <glibmm/regex.h>
26#include <glibmm/i18n.h>
27#include <glibmm/miscutils.h>
28#include <glibmm/convert.h>
29#include <glibmm/main.h>
30#include <gtkmm/icontheme.h>
31#include <gtkmm/label.h>
32#include <gtkmm/messagedialog.h>
33#include <gtkmm/recentmanager.h>
34#include <gtkmm/textbuffer.h>
71#define DESKTOP_IS_ACTIVE(d) (INKSCAPE._desktops != nullptr && !INKSCAPE._desktops->empty() && ((d) == INKSCAPE._desktops->front()))
108 g_error(
"Attempt to unref an Application (=%p) not the current instance (=%p) (maybe it's already been destroyed?)",
155 g_error(
"Inkscape::Application does not yet exist.");
173 auto extensiondir_shared = get_path_string(SHARED, EXTENSIONS);
174 if (!extensiondir_shared.empty()) {
175 std::string pythonpath = extensiondir_shared;
176 auto pythonpath_old = Glib::getenv(
"PYTHONPATH");
177 if (!pythonpath_old.empty()) {
178 pythonpath += G_SEARCHPATH_SEPARATOR + pythonpath_old;
180 Glib::setenv(
"PYTHONPATH", pythonpath);
199 Glib::ustring secondary;
208 auto display = Gdk::Display::get_default();
209 auto icon_theme = Gtk::IconTheme::get_for_display(display);
210 auto search_paths =
icon_theme->get_search_path();
212 for (
auto type : {USER, SHARED, SYSTEM}) {
213 auto path = get_path_string(type, ICONS);
215 search_paths.insert(search_paths.begin(), path);
230 Glib::ustring ui_language = prefs->
getString(
"/ui/language");
231 if(!ui_language.empty())
233 Glib::setenv(
"LANGUAGE", ui_language.raw(),
true);
239 Glib::setenv(
"LANG", ui_language.raw(),
true);
247 mapalt(guint(prefs->
getInt(
"/options/mapalt/value", 0)));
258 if (prefs->
getBool(
"/options/font/use_fontsdir_system",
true)) {
259 char const *fontsdir = get_path(SYSTEM, FONTS);
260 factory.AddFontsDir(fontsdir);
263 if (prefs->
getBool(
"/options/font/use_fontsdir_user",
true)) {
264 char const *fontsdirshared = get_path(SHARED, FONTS);
265 if (fontsdirshared) {
266 factory.AddFontsDir(fontsdirshared);
268 char const *fontsdir = get_path(USER, FONTS);
269 factory.AddFontsDir(fontsdir);
271 Glib::ustring fontdirs_pref = prefs->
getString(
"/options/font/custom_fontdirs");
272 std::vector<Glib::ustring> fontdirs = Glib::Regex::split_simple(
"\\|", fontdirs_pref);
273 for (
auto &fontdir : fontdirs) {
274 factory.AddFontsDir(fontdir.c_str());
281 g_error(
"FATAL: desktops still in list on application destruction!");
297 if ( maskvalue < 2 || maskvalue > 5 ) {
300 _mapalt = (GDK_ALT_MASK << (maskvalue-1));
311 static bool recursion =
false;
333 EventTracker<SimpleEvent<Inkscape::Debug::Event::CORE> > tracker(
"crash");
334 tracker.set<SimpleEvent<> >(
"emergency-save");
336 fprintf(stderr,
"\nEmergency save activated!\n");
338 time_t sptime = time (
nullptr);
339 struct tm *sptm = localtime (&sptime);
341 strftime(sptstr, 256,
"%Y_%m_%d_%H_%M_%S", sptm);
344 gchar *curdir = g_get_current_dir();
345 std::vector<gchar *> savednames;
346 std::vector<gchar *> failednames;
347 for (
auto doc : INKSCAPE._document_set) {
349 repr = doc->getReprRoot();
350 if (doc->isModifiedSinceSave()) {
351 const gchar *docname;
356 docname = doc->getDocumentName();
359 const char* d0 = strrchr ((
char*)docname,
'.');
360 if (d0 && (d0 > docname)) {
362 unsigned int dots = 0;
363 while ((isdigit (*d) || *d==
'_' || *d==
'.') && d>docname &&
dots<2) {
367 if (*d==
'.' && d>docname &&
dots==2) {
368 size_t len =
MIN (d - docname, 63);
369 memcpy (n, docname,
len);
375 if (!docname || !*docname) docname =
"emergency";
379 g_snprintf (
c, 1024,
"%.256s.%s.%d.svg", docname, sptstr, count);
381 const char* document_filename = doc->getDocumentFilename();
382 char* document_base =
nullptr;
383 if (document_filename) {
384 document_base = g_path_get_dirname(document_filename);
388 const char* locations[] = {
395 FILE *file =
nullptr;
396 for(
auto & location : locations) {
397 if (!location)
continue;
398 gchar * filename = g_build_filename(location,
c,
nullptr);
402 g_snprintf (
c, 1024,
"%s", filename);
407 g_free(document_base);
413 savednames.push_back(g_strdup (
c));
417 auto recentmanager = Gtk::RecentManager::get_default();
418 if (recentmanager && Glib::path_is_absolute(
c)) {
419 Glib::ustring uri = Glib::filename_to_uri(
c);
420 recentmanager->add_item(uri, {
422 "Emergency Saved Image",
424 "org.inkscape.Inkscape",
431 failednames.push_back((doc->getDocumentName()) ? g_strdup(doc->getDocumentName()) : g_strdup (_(
"Untitled document")));
438 if (!savednames.empty()) {
439 fprintf (stderr,
"\nEmergency save document locations:\n");
440 for (
auto i:savednames) {
441 fprintf (stderr,
" %s\n", i);
444 if (!failednames.empty()) {
445 fprintf (stderr,
"\nFailed to do emergency save for documents:\n");
446 for (
auto i:failednames) {
447 fprintf (stderr,
" %s\n", i);
454 fprintf (stderr,
"Emergency save completed. Inkscape will close now.\n");
455 fprintf (stderr,
"If you can reproduce this crash, please file a bug at https://inkscape.org/report\n");
456 fprintf (stderr,
"with a detailed description of the steps leading to the crash, so we can fix it.\n");
460 char const *istr =
"";
461 char const *sstr = _(
"Automatic backups of unsaved documents were done to the following locations:\n");
462 char const *fstr = _(
"Automatic backup of the following documents failed:\n");
463 gint nllen = strlen (
"\n");
464 gint
len = strlen (istr) + strlen (sstr) + strlen (fstr);
465 for (
auto i:savednames) {
468 for (
auto i:failednames) {
472 gchar *b = g_new (gchar,
len);
475 memcpy (b + pos, istr,
len);
477 if (!savednames.empty()) {
479 memcpy (b + pos, sstr,
len);
481 for (
auto i:savednames) {
485 memcpy (b + pos, i,
len);
487 memcpy (b + pos,
"\n", nllen);
491 if (!failednames.empty()) {
493 memcpy (b + pos, fstr,
len);
495 for (
auto i:failednames) {
499 memcpy (b + pos, i,
len);
501 memcpy (b + pos,
"\n", nllen);
509 auto mainloop = Glib::MainLoop::create();
511 auto &autosaves = UI::get_widget<Gtk::Label>(
builder,
"autosaves");
512 if (std::strlen(b) == 0) {
513 autosaves.set_visible(
false);
515 autosaves.set_label(b);
517 UI::get_object<Gtk::TextBuffer>(
builder,
"stacktrace")->set_text(
"<pre>\n" + boost::stacktrace::to_string(boost::stacktrace::stacktrace()) +
"</pre>\n<details><summary>System info</summary>\n" +
debug_info() +
"\n</details>");
518 auto &window = UI::get_widget<Gtk::Window>(
builder,
"crash_dialog");
519 auto &button_ok = UI::get_widget<Gtk::Button>(
builder,
"button_ok");
520 button_ok.signal_clicked().connect([&] { window.close(); });
521 button_ok.grab_focus();
522 window.signal_close_request().connect([&] { mainloop->quit();
return false; },
true);
526 }
catch (
const Glib::Error &ex) {
527 g_message(
"Glade file loading failed for crash handler... Anyway, error was: %s", b);
528 std::cerr << boost::stacktrace::stacktrace();
531 g_message(
"Error: %s", b );
532 std::cerr << boost::stacktrace::stacktrace();
548 g_return_if_fail (
desktop !=
nullptr);
554 g_error(
"Attempted to add desktop already in list.");
569 g_return_if_fail (
desktop !=
nullptr);
572 g_error(
"Attempted to remove desktop not in list.");
576 if (DESKTOP_IS_ACTIVE (
desktop)) {
607 g_return_if_fail (
desktop !=
nullptr);
609 if (DESKTOP_IS_ACTIVE (
desktop)) {
613 std::vector<SPDesktop*>::iterator i;
616 g_error(
"Tried to activate desktop not added to list.");
638 g_return_if_fail (
desktop !=
nullptr);
640 if (DESKTOP_IS_ACTIVE (
desktop)) {
651 if (_desktop->dkey == dkey){
662 unsigned int dkey = 0;
665 if (_desktop->dkey > dkey){
666 dkey = _desktop->
dkey;
678 unsigned int dkey_current = (
_desktops->front())->dkey;
682 for (
unsigned int i = dkey_current + 1; i <=
maximum_dkey(); ++i) {
708 unsigned int dkey_current = (
_desktops->front())->dkey;
710 if (dkey_current > 0) {
712 for (
signed int i = dkey_current - 1; i >= 0; --i) {
771 if (SP_ACTIVE_DESKTOP) {
772 return SP_ACTIVE_DESKTOP->getDocument();
static Inkscape::Application * _S_inst
sigc::signal< void(SPDesktop *)> signal_deactivate_desktop
static bool exists()
Checks whether the current Inkscape::Application global object exists.
Inkscape::UI::ThemeContext * themecontext
SPDesktop * prev_desktop()
void activate_desktop(SPDesktop *desktop)
std::set< SPDocument * > _document_set
void reactivate_desktop(SPDesktop *desktop)
Resends ACTIVATE_DESKTOP for current desktop; needed when a new desktop has got its window that dialo...
Application(bool use_gui)
void switch_desktops_prev()
SPDesktop * next_desktop()
SPDocument * active_document()
void add_document(SPDocument *document)
static void create(bool use_gui)
Creates a new Inkscape::Application global object.
void add_desktop(SPDesktop *desktop)
SPDesktop * find_desktop_by_dkey(unsigned int dkey)
void switch_desktops_next()
std::vector< SPDesktop * > * _desktops
sigc::signal< void(SPDesktop *)> signal_activate_desktop
sigc::signal< void(Inkscape::Selection *)> signal_selection_set
Application * operator&() const
Defined only for debugging purposes.
sigc::signal< void()> signal_external_change
sigc::signal< void(Inkscape::Selection *)> signal_selection_changed
static Application & instance()
Returns the current Inkscape::Application global object.
void get_all_desktops(std::list< SPDesktop * > &listbuf)
unsigned int maximum_dkey()
static bool _crashIsHappening
void exit()
Handler for Inkscape's Exit verb.
static void crash_handler(int signum)
SPDesktop * active_desktop()
void remove_desktop(SPDesktop *desktop)
void remove_document(SPDocument *document)
void handleError(Glib::ustring const &primary, Glib::ustring const &secondary) const
void clear()
Unselects all selected objects.
Preference storage class.
bool getBool(Glib::ustring const &pref_path, bool def=false)
Retrieve a Boolean value.
Glib::ustring getString(Glib::ustring const &pref_path, Glib::ustring const &def="")
Retrieve an UTF-8 string.
static Preferences * get()
Access the singleton Preferences object.
bool getLastError(Glib::ustring &primary, Glib::ustring &secondary)
Return details of the last encountered error, if any.
int getInt(Glib::ustring const &pref_path, int def=0)
Retrieve an integer.
void setErrorHandler(ErrorReporter *handler)
static void unload(bool save=true)
Unload all preferences.
double getDoubleLimited(Glib::ustring const &pref_path, double def=0.0, double min=DBL_MIN, double max=DBL_MAX, Glib::ustring const &unit="")
Retrieve a limited floating point value.
void themechangecallback()
void add_gtk_css(bool only_providers, bool cached=false)
Add our CSS style sheets.
void adjustGlobalFontScale(double factor)
Set application-wide font size adjustment by a factor, where 1 is 100% (no change)
static void initialize_source_syntax_styles()
sigc::signal< void()> getChangeThemeSignal()
static Glib::ustring get_font_scale_pref_path()
static FontFactory & get(Args &&... args)
Interface for refcounted XML nodes.
virtual Document * document()=0
Get the node's associated document.
To do: update description of desktop.
Inkscape::Selection * getSelection() const
Typed SVG document implementation.
Glib::RefPtr< Gtk::IconTheme > icon_theme
Editable view implementation.
void sp_transientize(Gtk::Window &window)
Make the argument dialog transient to the currently active document window.
Event handler for dialog windows.
A window for floating docks.
static char const *const current
TODO: insert short description here.
Consolidates version info for Inkscape, its various dependencies and the OS we're running on.
Inkscape - An SVG editor.
static void(* fpe_handler)(int)
static void(* abrt_handler)(int)
static constexpr int SP_INDENT
void inkscape_unref(Inkscape::Application &in)
static void(* bus_handler)(int)
static void(* ill_handler)(int)
void inkscape_ref(Inkscape::Application &in)
C++ification TODO list.
static void(* segv_handler)(int)
Raw stack of active status messages.
void dump_fopen_call(char const *utf8name, char const *id)
FILE * fopen_utf8name(char const *utf8name, char const *mode)
Open a file with g_fopen().
Glib::RefPtr< Gtk::Builder > create_builder(const char *filename)
Helper class to stream background task notifications as a series of messages.
std::string debug_info()
Return full debug info.
TODO: insert short description here.
void sp_repr_save_stream(Document *doc, FILE *fp, gchar const *default_ns, bool compress, gchar const *const old_href_abs_base, gchar const *const new_href_abs_base)
Inkscape::IO::Resource - simple resource API.
SPRoot: SVG <svg> implementation.
Gtk <themes> helper code.
Glib::RefPtr< Gtk::Builder > builder