X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Finkscape.cpp;h=4309775675cd95924f7bb72ee6b2affc72059513;hb=b2240fc6ae4c426379a3f477acd08a6b14c68aad;hp=cd176c0cfbc7c883d9da135bde77211713fd4f08;hpb=1e595ddc34dd7090b285ed9f6fc8e125b9a264d9;p=inkscape.git diff --git a/src/inkscape.cpp b/src/inkscape.cpp index cd176c0cf..430977567 100644 --- a/src/inkscape.cpp +++ b/src/inkscape.cpp @@ -1,9 +1,7 @@ -#define __INKSCAPE_C__ - -/* - * Interface to main application - * - * Authors: +/** @file + * @brief Legacy interface to main application + */ +/* Authors: * Lauris Kaplinski * bulia byak * @@ -17,8 +15,9 @@ # include "config.h" #endif +#include -#include +#include #include "debug/simple-event.h" #include "debug/event-tracker.h" @@ -37,30 +36,32 @@ using Inkscape::Extension::Internal::PrintWin32; # include #endif -#include - +#include +#include +#include +#include #include #include - -#include -#include "helper/sp-marshal.h" -#include "dialogs/debugdialog.h" -#include "application/application.h" -#include "application/editor.h" -#include "preferences.h" - - -#include "document.h" +#include +#include +#include #include "desktop.h" #include "desktop-handles.h" -#include "selection.h" +#include "device-manager.h" +#include "document.h" #include "event-context.h" +#include "extension/db.h" +#include "extension/init.h" +#include "extension/output.h" +#include "extension/system.h" +//#include "helper/sp-marshal.h" #include "inkscape-private.h" -#include "prefs-utils.h" -#include "xml/repr.h" #include "io/sys.h" - -#include "extension/init.h" +#include "message-stack.h" +#include "preferences.h" +#include "selection.h" +#include "ui/dialog/debug.h" +#include "xml/repr.h" static Inkscape::Application *inkscape = NULL; @@ -90,8 +91,6 @@ enum { # FORWARD DECLARATIONS ################################*/ -gboolean inkscape_app_use_gui( Inkscape::Application const * app ); - static void inkscape_class_init (Inkscape::ApplicationClass *klass); static void inkscape_init (SPObject *object); static void inkscape_dispose (GObject *object); @@ -99,25 +98,17 @@ static void inkscape_dispose (GObject *object); static void inkscape_activate_desktop_private (Inkscape::Application *inkscape, SPDesktop *desktop); static void inkscape_deactivate_desktop_private (Inkscape::Application *inkscape, SPDesktop *desktop); -static bool inkscape_init_config (Inkscape::XML::Document *doc, const gchar *config_name, const gchar *skeleton, - unsigned int skel_size, - const gchar *e_mkdir, - const gchar *e_notdir, - const gchar *e_ccf, - const gchar *e_cwf, - const gchar *warn); - struct Inkscape::Application { GObject object; Inkscape::XML::Document *menus; - std::multiset document_set; - GSList *documents; + std::map document_set; GSList *desktops; gchar *argv0; gboolean dialogs_toggle; gboolean use_gui; // may want to consider a virtual function // for overriding things like the warning dlg's guint mapalt; + guint trackalt; }; struct Inkscape::ApplicationClass { @@ -146,14 +137,13 @@ static void (* segv_handler) (int) = SIG_DFL; static void (* abrt_handler) (int) = SIG_DFL; static void (* fpe_handler) (int) = SIG_DFL; static void (* ill_handler) (int) = SIG_DFL; +#ifndef WIN32 static void (* bus_handler) (int) = SIG_DFL; - -#ifdef WIN32 -#define INKSCAPE_PROFILE_DIR "Inkscape" -#else -#define INKSCAPE_PROFILE_DIR ".inkscape" #endif +#define INKSCAPE_PROFILE_DIR "inkscape" +#define INKSCAPE_PROFILE_DIR_047DEV "Inkscape" +#define INKSCAPE_LEGACY_PROFILE_DIR ".inkscape" #define MENUS_FILE "menus.xml" @@ -199,7 +189,7 @@ inkscape_class_init (Inkscape::ApplicationClass * klass) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (Inkscape::ApplicationClass, modify_selection), NULL, NULL, - sp_marshal_NONE__POINTER_UINT, + g_cclosure_marshal_VOID__UINT_POINTER, G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT); inkscape_signals[CHANGE_SELECTION] = g_signal_new ("change_selection", @@ -207,7 +197,7 @@ inkscape_class_init (Inkscape::ApplicationClass * klass) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (Inkscape::ApplicationClass, change_selection), NULL, NULL, - sp_marshal_NONE__POINTER, + g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); inkscape_signals[CHANGE_SUBSELECTION] = g_signal_new ("change_subselection", @@ -215,7 +205,7 @@ inkscape_class_init (Inkscape::ApplicationClass * klass) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (Inkscape::ApplicationClass, change_subselection), NULL, NULL, - sp_marshal_NONE__POINTER, + g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); inkscape_signals[SET_SELECTION] = g_signal_new ("set_selection", @@ -223,7 +213,7 @@ inkscape_class_init (Inkscape::ApplicationClass * klass) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (Inkscape::ApplicationClass, set_selection), NULL, NULL, - sp_marshal_NONE__POINTER, + g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); inkscape_signals[SET_EVENTCONTEXT] = g_signal_new ("set_eventcontext", @@ -231,7 +221,7 @@ inkscape_class_init (Inkscape::ApplicationClass * klass) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (Inkscape::ApplicationClass, set_eventcontext), NULL, NULL, - sp_marshal_NONE__POINTER, + g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); inkscape_signals[ACTIVATE_DESKTOP] = g_signal_new ("activate_desktop", @@ -239,7 +229,7 @@ inkscape_class_init (Inkscape::ApplicationClass * klass) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (Inkscape::ApplicationClass, activate_desktop), NULL, NULL, - sp_marshal_NONE__POINTER, + g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); inkscape_signals[DEACTIVATE_DESKTOP] = g_signal_new ("deactivate_desktop", @@ -247,7 +237,7 @@ inkscape_class_init (Inkscape::ApplicationClass * klass) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (Inkscape::ApplicationClass, deactivate_desktop), NULL, NULL, - sp_marshal_NONE__POINTER, + g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); inkscape_signals[SHUTDOWN_SIGNAL] = g_signal_new ("shut_down", @@ -285,6 +275,180 @@ inkscape_class_init (Inkscape::ApplicationClass * klass) klass->deactivate_desktop = inkscape_deactivate_desktop_private; } +#ifdef WIN32 +typedef int uid_t; +#define getuid() 0 +#endif + +/** + * static gint inkscape_autosave(gpointer); + * + * Callback passed to g_timeout_add_seconds() + * Responsible for autosaving all open documents + */ +static gint inkscape_autosave(gpointer) +{ + if (inkscape->document_set.empty()) { // nothing to autosave + return TRUE; + } + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + // Use UID for separating autosave-documents between users if directory is multiuser + uid_t uid = getuid(); + + Glib::ustring autosave_dir; + { + Glib::ustring tmp = prefs->getString("/options/autosave/path"); + if (!tmp.empty()) { + autosave_dir = tmp; + } else { + autosave_dir = Glib::get_tmp_dir(); + } + } + + GDir *autosave_dir_ptr = g_dir_open(autosave_dir.c_str(), 0, NULL); + if( !autosave_dir_ptr ){ + g_warning("Cannot open autosave directory!"); + return TRUE; + } + + time_t sptime = time(NULL); + struct tm *sptm = localtime(&sptime); + gchar sptstr[256]; + strftime(sptstr, 256, "%Y_%m_%d_%H_%M_%S", sptm); + + gint autosave_max = prefs->getInt("/options/autosave/max", 10); + + gint docnum = 0; + + SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Autosaving documents...")); + for (std::map::iterator iter = inkscape->document_set.begin(); + iter != inkscape->document_set.end(); + ++iter) { + + SPDocument *doc = iter->first; + + ++docnum; + + Inkscape::XML::Node *repr = doc->getReprRoot(); + // g_debug("Document %d: \"%s\" %s", docnum, doc ? doc->getName() : "(null)", doc ? (doc->isModifiedSinceSave() ? "(dirty)" : "(clean)") : "(null)"); + + if (doc->isModifiedSinceSave()) { + gchar *oldest_autosave = 0; + const gchar *filename = 0; + struct stat sb; + time_t min_time = 0; + gint count = 0; + + // Look for previous autosaves + gchar* baseName = g_strdup_printf( "inkscape-autosave-%d", uid ); + g_dir_rewind(autosave_dir_ptr); + while( (filename = g_dir_read_name(autosave_dir_ptr)) != NULL ){ + if ( strncmp(filename, baseName, strlen(baseName)) == 0 ){ + gchar* full_path = g_build_filename( autosave_dir.c_str(), filename, NULL ); + if ( g_stat(full_path, &sb) != -1 ) { + if ( difftime(sb.st_ctime, min_time) < 0 || min_time == 0 ){ + min_time = sb.st_ctime; + if ( oldest_autosave ) { + g_free(oldest_autosave); + } + oldest_autosave = g_strdup(full_path); + } + count ++; + } + g_free(full_path); + } + } + + // g_debug("%d previous autosaves exists. Max = %d", count, autosave_max); + + // Have we reached the limit for number of autosaves? + if ( count >= autosave_max ){ + // Remove the oldest file + if ( oldest_autosave ) { + unlink(oldest_autosave); + } + } + + if ( oldest_autosave ) { + g_free(oldest_autosave); + oldest_autosave = 0; + } + + + // Set the filename we will actually save to + g_free(baseName); + baseName = g_strdup_printf("inkscape-autosave-%d-%s-%03d.svg", uid, sptstr, docnum); + gchar* full_path = g_build_filename(autosave_dir.c_str(), baseName, NULL); + g_free(baseName); + baseName = 0; + + // g_debug("Filename: %s", full_path); + + // Try to save the file + FILE *file = Inkscape::IO::fopen_utf8name(full_path, "w"); + gchar *errortext = 0; + if (file) { + try{ + sp_repr_save_stream(repr->document(), file, SP_SVG_NS_URI); + } catch (Inkscape::Extension::Output::no_extension_found &e) { + errortext = g_strdup(_("Autosave failed! Could not find inkscape extension to save document.")); + } catch (Inkscape::Extension::Output::save_failed &e) { + gchar *safeUri = Inkscape::IO::sanitizeString(full_path); + errortext = g_strdup_printf(_("Autosave failed! File %s could not be saved."), safeUri); + g_free(safeUri); + } + fclose(file); + } + else { + gchar *safeUri = Inkscape::IO::sanitizeString(full_path); + errortext = g_strdup_printf(_("Autosave failed! File %s could not be saved."), safeUri); + g_free(safeUri); + } + + if (errortext) { + SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, errortext); + g_warning("%s", errortext); + g_free(errortext); + } + + g_free(full_path); + } + } + g_dir_close(autosave_dir_ptr); + + SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Autosave complete.")); + + return TRUE; +} + +void inkscape_autosave_init() +{ + static guint32 autosave_timeout_id = 0; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + // Turn off any previously initiated timeouts + if ( autosave_timeout_id ) { + g_source_remove(autosave_timeout_id); + autosave_timeout_id = 0; + } + + // g_debug("options.autosave.enable = %d", prefs->getBool("/options/autosave/enable", true)); + // Is autosave enabled? + if (!prefs->getBool("/options/autosave/enable", true)){ + autosave_timeout_id = 0; + } else { + // Turn on autosave + guint32 timeout = prefs->getInt("/options/autosave/interval", 10) * 60; + // g_debug("options.autosave.interval = %d", prefs->getInt("/options/autosave/interval", 10)); +#if GLIB_CHECK_VERSION(2,14,0) + autosave_timeout_id = g_timeout_add_seconds(timeout, inkscape_autosave, NULL); +#else + autosave_timeout_id = g_timeout_add(timeout * 1000, inkscape_autosave, NULL); +#endif + } +} + static void inkscape_init (SPObject * object) @@ -295,16 +459,13 @@ inkscape_init (SPObject * object) g_assert_not_reached (); } - new (&inkscape->document_set) std::multiset(); + new (&inkscape->document_set) std::map(); inkscape->menus = sp_repr_read_mem (_(menus_skeleton), MENUS_SKELETON_SIZE, NULL); - - inkscape->documents = NULL; inkscape->desktops = NULL; - inkscape->dialogs_toggle = TRUE; - - inkscape->mapalt=GDK_MOD1_MASK; + inkscape->mapalt = GDK_MOD1_MASK; + inkscape->trackalt = FALSE; } static void @@ -312,14 +473,9 @@ inkscape_dispose (GObject *object) { Inkscape::Application *inkscape = (Inkscape::Application *) object; - while (inkscape->documents) { - // we don't otherwise unref, so why here? - sp_document_unref((SPDocument *)inkscape->documents->data); - } - g_assert (!inkscape->desktops); - Inkscape::Preferences::save(); + Inkscape::Preferences::unload(); if (inkscape->menus) { /* fixme: This is not the best place */ @@ -327,7 +483,7 @@ inkscape_dispose (GObject *object) inkscape->menus = NULL; } - inkscape->document_set.~multiset(); + inkscape->document_set.~map(); G_OBJECT_CLASS (parent_class)->dispose (object); @@ -367,6 +523,17 @@ void inkscape_mapalt(guint maskvalue) } } +guint +inkscape_trackalt() { + return inkscape->trackalt; +} + +void inkscape_trackalt(guint trackvalue) +{ + inkscape->trackalt = trackvalue; +} + + static void inkscape_activate_desktop_private (Inkscape::Application */*inkscape*/, SPDesktop *desktop) { @@ -386,6 +553,13 @@ inkscape_deactivate_desktop_private (Inkscape::Application */*inkscape*/, SPDesk #define SP_INDENT 8 +static bool crashIsHappening = false; + +bool inkscapeIsCrashing() +{ + return crashIsHappening; +} + static void inkscape_crash_handler (int /*signum*/) { @@ -395,7 +569,7 @@ inkscape_crash_handler (int /*signum*/) static gint recursion = FALSE; - /* + /* * reset all signal handlers: any further crashes should just be allowed * to crash normally. * */ @@ -406,13 +580,15 @@ inkscape_crash_handler (int /*signum*/) #ifndef WIN32 signal (SIGBUS, bus_handler ); #endif - + /* Stop bizarre loops */ if (recursion) { abort (); } recursion = TRUE; + crashIsHappening = true; + EventTracker > tracker("crash"); tracker.set >("emergency-save"); @@ -424,68 +600,80 @@ inkscape_crash_handler (int /*signum*/) strftime (sptstr, 256, "%Y_%m_%d_%H_%M_%S", sptm); gint count = 0; + gchar *curdir = g_get_current_dir(); // This one needs to be freed explicitly + gchar *inkscapedir = g_path_get_dirname(INKSCAPE->argv0); // Needs to be freed GSList *savednames = NULL; GSList *failednames = NULL; - for (GSList *l = inkscape->documents; l != NULL; l = l->next) { - SPDocument *doc; + for (std::map::iterator iter = inkscape->document_set.begin(); + iter != inkscape->document_set.end(); + ++iter) { + SPDocument *doc = iter->first; Inkscape::XML::Node *repr; - doc = (SPDocument *) l->data; - repr = sp_document_repr_root (doc); + repr = doc->getReprRoot(); if (doc->isModifiedSinceSave()) { - const gchar *docname, *d0, *d; - gchar n[64], c[1024]; - FILE *file; + const gchar *docname; /* originally, the document name was retrieved from * the sodipod:docname attribute */ - docname = doc->name; + docname = doc->getName(); if (docname) { - /* fixme: Quick hack to remove emergency file suffix */ - d0 = strrchr ((char*)docname, '.'); + /* Removes an emergency save suffix if present: /(.*)\.[0-9_]*\.[0-9_]*\.[~\.]*$/\1/ */ + const char* d0 = strrchr ((char*)docname, '.'); if (d0 && (d0 > docname)) { - d0 = strrchr ((char*)(d0 - 1), '.'); - if (d0 && (d0 > docname)) { - d = d0; - while (isdigit (*d) || (*d == '.') || (*d == '_')) d += 1; - if (*d) { - memcpy (n, docname, MIN (d0 - docname - 1, 64)); - n[63] = '\0'; - docname = n; - } + const char* d = d0; + unsigned int dots = 0; + while ((isdigit (*d) || *d=='_' || *d=='.') && d>docname && dots<2) { + d -= 1; + if (*d=='.') dots++; + } + if (*d=='.' && d>docname && dots==2) { + char n[64]; + size_t len = MIN (d - docname, 63); + memcpy (n, docname, len); + n[len] = '\0'; + docname = n; } } } - if (!docname || !*docname) docname = "emergency"; - // try saving to the profile location - g_snprintf (c, 1024, "%.256s.%s.%d", docname, sptstr, count); - gchar * location = homedir_path(c); - Inkscape::IO::dump_fopen_call(location, "E"); - file = Inkscape::IO::fopen_utf8name(location, "w"); - g_free(location); - if (!file) { - // try saving to /tmp - g_snprintf (c, 1024, "/tmp/inkscape-%.256s.%s.%d", docname, sptstr, count); - Inkscape::IO::dump_fopen_call(c, "G"); - file = Inkscape::IO::fopen_utf8name(c, "w"); - } - if (!file) { - // try saving to the current directory - g_snprintf (c, 1024, "inkscape-%.256s.%s.%d", docname, sptstr, count); - Inkscape::IO::dump_fopen_call(c, "F"); - file = Inkscape::IO::fopen_utf8name(c, "w"); + + // Emergency filename + char c[1024]; + g_snprintf (c, 1024, "%.256s.%s.%d.svg", docname, sptstr, count); + + // Find a location + const char* locations[] = { + doc->getBase(), + g_get_home_dir(), + g_get_tmp_dir(), + curdir, + inkscapedir + }; + FILE *file = 0; + for(size_t i=0; idocument(), file, SP_SVG_NS_URI); savednames = g_slist_prepend (savednames, g_strdup (c)); fclose (file); } else { - docname = repr->attribute("sodipodi:docname"); - failednames = g_slist_prepend (failednames, (docname) ? g_strdup (docname) : g_strdup (_("Untitled document"))); + failednames = g_slist_prepend (failednames, (doc->getName()) ? g_strdup(doc->getName()) : g_strdup (_("Untitled document"))); } count++; } } + g_free(curdir); + g_free(inkscapedir); savednames = g_slist_reverse (savednames); failednames = g_slist_reverse (failednames); @@ -502,7 +690,8 @@ inkscape_crash_handler (int /*signum*/) } } - Inkscape::Preferences::save(); + // do not save the preferences since they can be in a corrupted state + Inkscape::Preferences::unload(false); fprintf (stderr, "Emergency save completed. Inkscape will close now.\n"); fprintf (stderr, "If you can reproduce this crash, please file a bug at www.inkscape.org\n"); @@ -557,7 +746,7 @@ inkscape_crash_handler (int /*signum*/) } *(b + pos) = '\0'; - if ( inkscape_get_instance() && inkscape_app_use_gui( inkscape_get_instance() ) ) { + if ( inkscape_get_instance() && inkscape_use_gui() ) { GtkWidget *msgbox = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", b); gtk_dialog_run (GTK_DIALOG (msgbox)); gtk_widget_destroy (msgbox); @@ -575,6 +764,28 @@ inkscape_crash_handler (int /*signum*/) } +class InkErrorHandler : public Inkscape::ErrorReporter { +public: + InkErrorHandler(bool useGui) : Inkscape::ErrorReporter(), + _useGui(useGui) + {} + virtual ~InkErrorHandler() {} + + virtual void handleError( Glib::ustring const& primary, Glib::ustring const& secondary ) const + { + if (_useGui) { + Gtk::MessageDialog err(primary, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true); + err.set_secondary_text(secondary); + err.run(); + } else { + g_message("%s", primary.data()); + g_message("%s", secondary.data()); + } + } + +private: + bool _useGui; +}; void inkscape_application_init (const gchar *argv0, gboolean use_gui) @@ -593,34 +804,56 @@ inkscape_application_init (const gchar *argv0, gboolean use_gui) inkscape->use_gui = use_gui; inkscape->argv0 = g_strdup(argv0); - /* Attempt to load the preferences, and set the save_preferences flag to TRUE - if we could, or FALSE if we couldn't */ - Inkscape::Preferences::load(); - inkscape_load_menus(inkscape); + /* Load the preferences and menus */ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + InkErrorHandler* handler = new InkErrorHandler(use_gui); + prefs->setErrorHandler(handler); + { + Glib::ustring msg; + Glib::ustring secondary; + if (prefs->getLastError( msg, secondary )) { + handler->handleError(msg, secondary); + } + } + + if (use_gui) { + inkscape_load_menus(inkscape); + Inkscape::DeviceManager::getManager().loadConfig(); + } + + /* set language for user interface according setting in preferences */ + Glib::ustring ui_language = prefs->getString("/ui/language"); + if(!ui_language.empty()) + { + setenv("LANGUAGE", ui_language, 1); + } /* DebugDialog redirection. On Linux, default to OFF, on Win32, default to ON. - * Use only if use_gui is enabled - */ + * Use only if use_gui is enabled + */ #ifdef WIN32 #define DEFAULT_LOG_REDIRECT true #else #define DEFAULT_LOG_REDIRECT false #endif - if (use_gui == TRUE && prefs_get_int_attribute("dialogs.debug", "redirect", DEFAULT_LOG_REDIRECT)) + if (use_gui == TRUE && prefs->getBool("/dialogs/debug/redirect", DEFAULT_LOG_REDIRECT)) { - Inkscape::UI::Dialogs::DebugDialog::getInstance()->captureLogMessages(); + Inkscape::UI::Dialog::DebugDialog::getInstance()->captureLogMessages(); } /* Check for global remapping of Alt key */ - if(use_gui) + if (use_gui) { - inkscape_mapalt(guint(prefs_get_int_attribute("options.mapalt","value",0))); + inkscape_mapalt(guint(prefs->getInt("/options/mapalt/value", 0))); + inkscape_trackalt(guint(prefs->getInt("/options/trackalt/value", 0))); } /* Initialize the extensions */ Inkscape::Extension::init(); + inkscape_autosave_init(); + return; } @@ -633,176 +866,38 @@ inkscape_get_instance() return inkscape; } -gboolean inkscape_app_use_gui( Inkscape::Application const * app ) +gboolean inkscape_use_gui() { - return app->use_gui; -} - -/** - * Preference management - * We use '.' as separator - * - * Returns TRUE if the config file was successfully loaded, FALSE if not. - */ -bool -inkscape_load_config (const gchar *filename, Inkscape::XML::Document *config, const gchar *skeleton, - unsigned int skel_size, const gchar *e_notreg, const gchar *e_notxml, - const gchar *e_notsp, const gchar *warn) -{ - gchar *fn = profile_path(filename); - if (!Inkscape::IO::file_test(fn, G_FILE_TEST_EXISTS)) { - bool result; - /* No such file */ - result = inkscape_init_config (config, filename, skeleton, - skel_size, - _("Cannot create directory %s.\n%s"), - _("%s is not a valid directory.\n%s"), - _("Cannot create file %s.\n%s"), - _("Cannot write file %s.\n%s"), - _("Although Inkscape will run, it will use default settings,\n" - "and any changes made in preferences will not be saved.")); - g_free (fn); - return result; - } - - if (!Inkscape::IO::file_test(fn, G_FILE_TEST_IS_REGULAR)) { - /* Not a regular file */ - gchar *safeFn = Inkscape::IO::sanitizeString(fn); - GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_notreg, safeFn, warn); - gtk_dialog_run (GTK_DIALOG (w)); - gtk_widget_destroy (w); - g_free(safeFn); - g_free (fn); - return false; - } - - Inkscape::XML::Document *doc = sp_repr_read_file (fn, NULL); - if (doc == NULL) { - /* Not an valid xml file */ - gchar *safeFn = Inkscape::IO::sanitizeString(fn); - GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_notxml, safeFn, warn); - gtk_dialog_run (GTK_DIALOG (w)); - gtk_widget_destroy (w); - g_free(safeFn); - g_free (fn); - return false; - } - - Inkscape::XML::Node *root = doc->root(); - if (strcmp (root->name(), "inkscape")) { - gchar *safeFn = Inkscape::IO::sanitizeString(fn); - GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_notsp, safeFn, warn); - gtk_dialog_run (GTK_DIALOG (w)); - gtk_widget_destroy (w); - Inkscape::GC::release(doc); - g_free(safeFn); - g_free (fn); - return false; - } - - /** \todo this is a hack, need to figure out how to get - * a reasonable merge working with the menus.xml file */ - if (skel_size == MENUS_SKELETON_SIZE) { - if (INKSCAPE) - INKSCAPE->menus = doc; - doc = config; - } else { - config->root()->mergeFrom(doc->root(), "id"); - } - - Inkscape::GC::release(doc); - g_free (fn); - return true; + return inkscape_get_instance()->use_gui; } /** * Menus management * */ -bool -inkscape_load_menus (Inkscape::Application *inkscape) +bool inkscape_load_menus (Inkscape::Application */*inkscape*/) { + // TODO fix that fn is being leaked gchar *fn = profile_path(MENUS_FILE); - bool retval = false; - if (Inkscape::IO::file_test(fn, G_FILE_TEST_EXISTS)) { - retval = inkscape_load_config (MENUS_FILE, - inkscape->menus, - menus_skeleton, - MENUS_SKELETON_SIZE, - _("%s is not a regular file.\n%s"), - _("%s not a valid XML file, or\n" - "you don't have read permissions on it.\n%s"), - _("%s is not a valid menus file.\n%s"), - _("Inkscape will run with default menus.\n" - "New menus will not be saved.")); - } else { - INKSCAPE->menus = sp_repr_read_mem(menus_skeleton, MENUS_SKELETON_SIZE, NULL); - if (INKSCAPE->menus != NULL) - retval = true; - } - g_free(fn); - return retval; -} - -/** - * We use '.' as separator - * \param inkscape Unused - */ -Inkscape::XML::Node * -inkscape_get_repr (Inkscape::Application *inkscape, const gchar *key) -{ - if ( (key == NULL) || (inkscape == NULL) ) { - return NULL; - } - - Inkscape::XML::Node *prefs = Inkscape::Preferences::get(); - if ( !prefs ) { - return NULL; - } - - Inkscape::XML::Node *repr = prefs->root(); - if (!repr) return NULL; - g_assert (!(strcmp (repr->name(), "inkscape"))); - - gchar const *s = key; - while ((s) && (*s)) { - - /* Find next name */ - gchar const *e = strchr (s, '.'); - guint len; - if (e) { - len = e++ - s; - } else { - len = strlen (s); - } - - Inkscape::XML::Node* child; - for (child = repr->firstChild(); child != NULL; child = child->next()) { - gchar const *id = child->attribute("id"); - if ((id) && (strlen (id) == len) && (!strncmp (id, s, len))) - { - break; - } - } - if (child == NULL) { - return NULL; + gchar *menus_xml = NULL; + gsize len = 0; + + if (g_file_get_contents(fn, &menus_xml, &len, NULL)) { + // load the menus_xml file + INKSCAPE->menus = sp_repr_read_mem(menus_xml, len, NULL); + g_free(menus_xml); + if (INKSCAPE->menus) { + return true; } - - repr = child; - s = e; } - return repr; + INKSCAPE->menus = sp_repr_read_mem(menus_skeleton, MENUS_SKELETON_SIZE, NULL); + return (INKSCAPE->menus != 0); } - void inkscape_selection_modified (Inkscape::Selection *selection, guint flags) { - if (Inkscape::NSApplication::Application::getNewGui()) { - Inkscape::NSApplication::Editor::selectionModified (selection, flags); - return; - } g_return_if_fail (selection != NULL); if (DESKTOP_IS_ACTIVE (selection->desktop())) { @@ -814,10 +909,6 @@ inkscape_selection_modified (Inkscape::Selection *selection, guint flags) void inkscape_selection_changed (Inkscape::Selection * selection) { - if (Inkscape::NSApplication::Application::getNewGui()) { - Inkscape::NSApplication::Editor::selectionChanged (selection); - return; - } g_return_if_fail (selection != NULL); if (DESKTOP_IS_ACTIVE (selection->desktop())) { @@ -828,10 +919,6 @@ inkscape_selection_changed (Inkscape::Selection * selection) void inkscape_subselection_changed (SPDesktop *desktop) { - if (Inkscape::NSApplication::Application::getNewGui()) { - Inkscape::NSApplication::Editor::subSelectionChanged (desktop); - return; - } g_return_if_fail (desktop != NULL); if (DESKTOP_IS_ACTIVE (desktop)) { @@ -843,10 +930,6 @@ inkscape_subselection_changed (SPDesktop *desktop) void inkscape_selection_set (Inkscape::Selection * selection) { - if (Inkscape::NSApplication::Application::getNewGui()) { - Inkscape::NSApplication::Editor::selectionSet (selection); - return; - } g_return_if_fail (selection != NULL); if (DESKTOP_IS_ACTIVE (selection->desktop())) { @@ -859,10 +942,6 @@ inkscape_selection_set (Inkscape::Selection * selection) void inkscape_eventcontext_set (SPEventContext * eventcontext) { - if (Inkscape::NSApplication::Application::getNewGui()) { - Inkscape::NSApplication::Editor::eventContextSet (eventcontext); - return; - } g_return_if_fail (eventcontext != NULL); g_return_if_fail (SP_IS_EVENT_CONTEXT (eventcontext)); @@ -876,24 +955,16 @@ void inkscape_add_desktop (SPDesktop * desktop) { g_return_if_fail (desktop != NULL); - - if (Inkscape::NSApplication::Application::getNewGui()) - { - Inkscape::NSApplication::Editor::addDesktop (desktop); - return; - } g_return_if_fail (inkscape != NULL); g_assert (!g_slist_find (inkscape->desktops, desktop)); - inkscape->desktops = g_slist_append (inkscape->desktops, desktop); + inkscape->desktops = g_slist_prepend (inkscape->desktops, desktop); - if (DESKTOP_IS_ACTIVE (desktop)) { - g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, desktop); - g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, sp_desktop_event_context (desktop)); - g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, sp_desktop_selection (desktop)); - g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, sp_desktop_selection (desktop)); - } + g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, desktop); + g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, sp_desktop_event_context (desktop)); + g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, sp_desktop_selection (desktop)); + g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, sp_desktop_selection (desktop)); } @@ -902,11 +973,6 @@ void inkscape_remove_desktop (SPDesktop * desktop) { g_return_if_fail (desktop != NULL); - if (Inkscape::NSApplication::Application::getNewGui()) - { - Inkscape::NSApplication::Editor::removeDesktop (desktop); - return; - } g_return_if_fail (inkscape != NULL); g_assert (g_slist_find (inkscape->desktops, desktop)); @@ -942,11 +1008,6 @@ void inkscape_activate_desktop (SPDesktop * desktop) { g_return_if_fail (desktop != NULL); - if (Inkscape::NSApplication::Application::getNewGui()) - { - Inkscape::NSApplication::Editor::activateDesktop (desktop); - return; - } g_return_if_fail (inkscape != NULL); if (DESKTOP_IS_ACTIVE (desktop)) { @@ -976,11 +1037,6 @@ void inkscape_reactivate_desktop (SPDesktop * desktop) { g_return_if_fail (desktop != NULL); - if (Inkscape::NSApplication::Application::getNewGui()) - { - Inkscape::NSApplication::Editor::reactivateDesktop (desktop); - return; - } g_return_if_fail (inkscape != NULL); if (DESKTOP_IS_ACTIVE (desktop)) @@ -1094,13 +1150,8 @@ inkscape_switch_desktops_prev () void inkscape_dialogs_hide () { - if (Inkscape::NSApplication::Application::getNewGui()) - Inkscape::NSApplication::Editor::hideDialogs(); - else - { - g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DIALOGS_HIDE], 0); - inkscape->dialogs_toggle = FALSE; - } + g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DIALOGS_HIDE], 0); + inkscape->dialogs_toggle = FALSE; } @@ -1108,13 +1159,8 @@ inkscape_dialogs_hide () void inkscape_dialogs_unhide () { - if (Inkscape::NSApplication::Application::getNewGui()) - Inkscape::NSApplication::Editor::unhideDialogs(); - else - { - g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DIALOGS_UNHIDE], 0); - inkscape->dialogs_toggle = TRUE; - } + g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DIALOGS_UNHIDE], 0); + inkscape->dialogs_toggle = TRUE; } @@ -1145,48 +1191,49 @@ inkscape_add_document (SPDocument *document) { g_return_if_fail (document != NULL); - if (!Inkscape::NSApplication::Application::getNewGui()) - { - if ( inkscape->document_set.find(document) != inkscape->document_set.end() ) { - - inkscape->documents = g_slist_append (inkscape->documents, document); - } - inkscape->document_set.insert(document); - } - else - { - Inkscape::NSApplication::Editor::addDocument (document); + // try to insert the pair into the list + if (!(inkscape->document_set.insert(std::make_pair(document, 1)).second)) { + //insert failed, this key (document) is already in the list + for (std::map::iterator iter = inkscape->document_set.begin(); + iter != inkscape->document_set.end(); + ++iter) { + if (iter->first == document) { + // found this document in list, increase its count + iter->second ++; + } + } } } - -void +// returns true if this was last reference to this document, so you can delete it +bool inkscape_remove_document (SPDocument *document) { - g_return_if_fail (document != NULL); - - if (!Inkscape::NSApplication::Application::getNewGui()) - { - inkscape->document_set.erase(document); - if ( inkscape->document_set.find(document) == inkscape->document_set.end() ) { - inkscape->documents = g_slist_remove (inkscape->documents, document); + g_return_val_if_fail (document != NULL, false); + + for (std::map::iterator iter = inkscape->document_set.begin(); + iter != inkscape->document_set.end(); + ++iter) { + if (iter->first == document) { + // found this document in list, decrease its count + iter->second --; + if (iter->second < 1) { + // this was the last one, remove the pair from list + inkscape->document_set.erase (iter); + return true; + } else { + return false; + } } } - else - { - Inkscape::NSApplication::Editor::removeDocument (document); - } - return; + return false; } SPDesktop * inkscape_active_desktop (void) { - if (Inkscape::NSApplication::Application::getNewGui()) - return Inkscape::NSApplication::Editor::getActiveDesktop(); - if (inkscape->desktops == NULL) { return NULL; } @@ -1197,9 +1244,6 @@ inkscape_active_desktop (void) SPDocument * inkscape_active_document (void) { - if (Inkscape::NSApplication::Application::getNewGui()) - return Inkscape::NSApplication::Editor::getActiveDocument(); - if (SP_ACTIVE_DESKTOP) { return sp_desktop_document (SP_ACTIVE_DESKTOP); } @@ -1238,120 +1282,6 @@ inkscape_active_event_context (void) # HELPERS #####################*/ -static bool -inkscape_init_config (Inkscape::XML::Document */*doc*/, const gchar *config_name, const gchar *skeleton, - unsigned int skel_size, - const gchar *e_mkdir, - const gchar *e_notdir, - const gchar *e_ccf, - const gchar *e_cwf, - const gchar *warn) -{ - gchar *dn = profile_path(NULL); - bool use_gui = (Inkscape::NSApplication::Application::getNewGui())? Inkscape::NSApplication::Application::getUseGui() : inkscape->use_gui; - if (!Inkscape::IO::file_test(dn, G_FILE_TEST_EXISTS)) { - if (Inkscape::IO::mkdir_utf8name(dn)) - { - if (use_gui) { - // Cannot create directory - gchar *safeDn = Inkscape::IO::sanitizeString(dn); - GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_mkdir, safeDn, warn); - gtk_dialog_run (GTK_DIALOG (w)); - gtk_widget_destroy (w); - g_free(safeDn); - g_free (dn); - return false; - } else { - g_warning(e_mkdir, dn, warn); - g_free (dn); - return false; - } - } - - // Also create (empty for now) subdirectories for the user's stuff - { - gchar *temp_dn = profile_path("templates"); - Inkscape::IO::mkdir_utf8name(temp_dn); - } - { - gchar *temp_dn = profile_path("keys"); - Inkscape::IO::mkdir_utf8name(temp_dn); - } - { - gchar *temp_dn = profile_path("icons"); - Inkscape::IO::mkdir_utf8name(temp_dn); - } - { - gchar *temp_dn = profile_path("extensions"); - Inkscape::IO::mkdir_utf8name(temp_dn); - } - { - gchar *temp_dn = profile_path("palettes"); - Inkscape::IO::mkdir_utf8name(temp_dn); - } - - } else if (!Inkscape::IO::file_test(dn, G_FILE_TEST_IS_DIR)) { - if (use_gui) { - // Not a directory - gchar *safeDn = Inkscape::IO::sanitizeString(dn); - GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_notdir, safeDn, warn); - gtk_dialog_run (GTK_DIALOG (w)); - gtk_widget_destroy (w); - g_free( safeDn ); - g_free (dn); - return false; - } else { - g_warning(e_notdir, dn, warn); - g_free(dn); - return false; - } - } - g_free (dn); - - gchar *fn = profile_path(config_name); - - Inkscape::IO::dump_fopen_call(fn, "H"); - FILE *fh = Inkscape::IO::fopen_utf8name(fn, "w"); - if (!fh) { - if (use_gui) { - /* Cannot create file */ - gchar *safeFn = Inkscape::IO::sanitizeString(fn); - GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_ccf, safeFn, warn); - gtk_dialog_run (GTK_DIALOG (w)); - gtk_widget_destroy (w); - g_free(safeFn); - g_free (fn); - return false; - } else { - g_warning(e_ccf, fn, warn); - g_free(fn); - return false; - } - } - if ( fwrite(skeleton, 1, skel_size, fh) != skel_size ) { - if (use_gui) { - /* Cannot create file */ - gchar *safeFn = Inkscape::IO::sanitizeString(fn); - GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_cwf, safeFn, warn); - gtk_dialog_run (GTK_DIALOG (w)); - gtk_widget_destroy (w); - g_free(safeFn); - g_free (fn); - fclose(fh); - return false; - } else { - g_warning(e_cwf, fn, warn); - g_free(fn); - fclose(fh); - return false; - } - } - - g_free(fn); - fclose(fh); - return true; -} - void inkscape_refresh_display (Inkscape::Application *inkscape) { @@ -1373,36 +1303,19 @@ inkscape_exit (Inkscape::Application */*inkscape*/) //emit shutdown signal so that dialogs could remember layout g_signal_emit (G_OBJECT (INKSCAPE), inkscape_signals[SHUTDOWN_SIGNAL], 0); - Inkscape::Preferences::save(); + Inkscape::Preferences::unload(); gtk_main_quit (); } -gchar * +char * homedir_path(const char *filename) { static const gchar *homedir = NULL; if (!homedir) { homedir = g_get_home_dir(); - gchar* utf8Path = g_filename_to_utf8( homedir, -1, NULL, NULL, NULL ); - if ( utf8Path ) - { - homedir = utf8Path; - if (!g_utf8_validate(homedir, -1, NULL)) { - g_warning( "g_get_home_dir() post A IS NOT UTF-8" ); - } - } } if (!homedir) { - gchar * path = g_path_get_dirname(INKSCAPE->argv0); - gchar* utf8Path = g_filename_to_utf8( path, -1, NULL, NULL, NULL ); - g_free(path); - if ( utf8Path ) - { - homedir = utf8Path; - if (!g_utf8_validate(homedir, -1, NULL)) { - g_warning( "g_get_home_dir() post B IS NOT UTF-8" ); - } - } + homedir = g_path_get_dirname(INKSCAPE->argv0); } return g_build_filename(homedir, filename, NULL); } @@ -1416,7 +1329,15 @@ gchar * profile_path(const char *filename) { static const gchar *prefdir = NULL; + + if (!prefdir) { + // First check for a custom environment variable for a "portable app" + gchar const *val = g_getenv("INKSCAPE_PORTABLE_PROFILE_DIR"); + if (val) { + prefdir = g_strdup(val); + } + #ifdef HAS_SHGetSpecialFolderLocation // prefer c:\Documents and Settings\UserName\Application Data\ to // c:\Documents and Settings\userName\; @@ -1461,13 +1382,58 @@ profile_path(const char *filename) } */ } + + if (prefdir) { + prefdir = g_build_filename(prefdir, INKSCAPE_PROFILE_DIR, NULL); + } } #endif if (!prefdir) { - prefdir = homedir_path(NULL); + prefdir = g_build_filename(g_get_user_config_dir(), INKSCAPE_PROFILE_DIR, NULL); + gchar * legacyDir = homedir_path(INKSCAPE_LEGACY_PROFILE_DIR); + gchar * dev47Dir = g_build_filename(g_get_user_config_dir(), INKSCAPE_PROFILE_DIR_047DEV, NULL); + + bool needsMigration = ( !Inkscape::IO::file_test( prefdir, G_FILE_TEST_EXISTS ) && Inkscape::IO::file_test( legacyDir, G_FILE_TEST_EXISTS ) ); + if (needsMigration) { + // TODO here is a point to hook in preference migration + g_warning("Preferences need to be migrated from 0.46 or older %s to %s", legacyDir, prefdir); + Inkscape::Preferences::migrate( legacyDir, prefdir ); + } + + bool needsRenameWarning = ( !Inkscape::IO::file_test( prefdir, G_FILE_TEST_EXISTS ) && Inkscape::IO::file_test( dev47Dir, G_FILE_TEST_EXISTS ) ); + if (needsRenameWarning) { + g_warning("Preferences need to be copied from %s to %s", legacyDir, prefdir); + } + + g_free(legacyDir); + legacyDir = 0; + g_free(dev47Dir); + dev47Dir = 0; + // In case the XDG user config dir of the moment does not yet exist... + int mode = S_IRWXU; +#ifdef S_IRGRP + mode |= S_IRGRP; +#endif +#ifdef S_IXGRP + mode |= S_IXGRP; +#endif +#ifdef S_IXOTH + mode |= S_IXOTH; +#endif + if ( g_mkdir_with_parents(prefdir, mode) == -1 ) { + int problem = errno; + g_warning("Unable to create profile directory (%s) (%d)", g_strerror(problem), problem); + } else { + gchar const *userDirs[] = {"keys", "templates", "icons", "extensions", "palettes", NULL}; + for (gchar const** name = userDirs; *name; ++name) { + gchar *dir = g_build_filename(prefdir, *name, NULL); + g_mkdir_with_parents(dir, mode); + g_free(dir); + } + } } } - return g_build_filename(prefdir, INKSCAPE_PROFILE_DIR, filename, NULL); + return g_build_filename(prefdir, filename, NULL); } Inkscape::XML::Node * @@ -1486,8 +1452,6 @@ inkscape_get_all_desktops(std::list< SPDesktop* >& listbuf) } } - - /* Local Variables: mode:c++