Code

Merge and cleanup of GSoC C++-ification project.
[inkscape.git] / src / inkscape.cpp
index 10857e94a797f598087b6220a7610adda41308de..4309775675cd95924f7bb72ee6b2affc72059513 100644 (file)
@@ -1,9 +1,7 @@
-#define __INKSCAPE_C__
-
-/*
- * Interface to main application
- *
- * Authors:
+/** @file
+ * @brief Legacy interface to main application
+ */
+/* Authors:
  *   Lauris Kaplinski <lauris@kaplinski.com>
  *   bulia byak <buliabyak@users.sf.net>
  *
@@ -17,8 +15,9 @@
 # include "config.h"
 #endif
 
+#include <errno.h>
 
-#include <set>
+#include <map>
 #include "debug/simple-event.h"
 #include "debug/event-tracker.h"
 
@@ -37,38 +36,32 @@ using Inkscape::Extension::Internal::PrintWin32;
 # include <shlobj.h>
 #endif
 
-#include <signal.h>
-
-#include <gtk/gtkmain.h>
-#include <gtk/gtkmessagedialog.h>
-#include <glib.h>
+#include <cstring>
 #include <glib/gstdio.h>
-
+#include <glib.h>
 #include <glibmm/i18n.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtkmessagedialog.h>
+#include <gtkmm/messagedialog.h>
+#include <signal.h>
 #include <string>
-#include <cstring>
-#include "helper/sp-marshal.h"
-#include "dialogs/debugdialog.h"
-#include "application/application.h"
-#include "application/editor.h"
-#include "preferences.h"
-
-
-#include "document.h"
 #include "desktop.h"
 #include "desktop-handles.h"
-#include "selection.h"
+#include "device-manager.h"
+#include "document.h"
 #include "event-context.h"
-#include "inkscape-private.h"
-#include "prefs-utils.h"
-#include "xml/repr.h"
-#include "io/sys.h"
-#include "message-stack.h"
-
-#include "extension/init.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 "io/sys.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;
 
@@ -98,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);
@@ -107,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<SPDocument *> document_set;
-    GSList *documents;
+    std::map<SPDocument *, int> 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 {
@@ -154,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"
 
 
@@ -207,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",
@@ -215,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",
@@ -223,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",
@@ -231,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",
@@ -239,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",
@@ -247,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",
@@ -255,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",
@@ -306,17 +288,18 @@ typedef int uid_t;
  */
 static gint inkscape_autosave(gpointer)
 {
-    if (!inkscape->documents) { // nothing to autosave
+    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;
     {
-        gchar const* tmp = prefs_get_string_attribute("options.autosave", "path");
-        if ( tmp ) {
+        Glib::ustring tmp = prefs->getString("/options/autosave/path");
+        if (!tmp.empty()) {
             autosave_dir = tmp;
         } else {
             autosave_dir = Glib::get_tmp_dir();
@@ -334,18 +317,21 @@ static gint inkscape_autosave(gpointer)
     gchar sptstr[256];
     strftime(sptstr, 256, "%Y_%m_%d_%H_%M_%S", sptm);
 
-    gint autosave_max = prefs_get_int_attribute("options.autosave", "max", 10);
+    gint autosave_max = prefs->getInt("/options/autosave/max", 10);
 
     gint docnum = 0;
 
     SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Autosaving documents..."));
-    for (GSList *docList = inkscape->documents; docList; docList = docList->next) {
+    for (std::map<SPDocument*,int>::iterator iter = inkscape->document_set.begin();
+          iter != inkscape->document_set.end();
+          ++iter) {
+
+        SPDocument *doc = iter->first;
+
         ++docnum;
 
-        // TODO replace this with SP_DOCUMENT() when linking issues are addressed:
-        SPDocument *doc = static_cast<SPDocument *>(docList->data);
-        Inkscape::XML::Node *repr = sp_document_repr_root(doc);
-        // g_debug("Document %d: \"%s\" %s", docnum, doc ? doc->name : "(null)", doc ? (doc->isModifiedSinceSave() ? "(dirty)" : "(clean)") : "(null)");
+        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;
@@ -353,7 +339,7 @@ static gint inkscape_autosave(gpointer)
             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);
@@ -375,7 +361,7 @@ static gint inkscape_autosave(gpointer)
             }
 
             // 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
@@ -439,6 +425,7 @@ static gint inkscape_autosave(gpointer)
 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 ) {
@@ -446,14 +433,14 @@ void inkscape_autosave_init()
         autosave_timeout_id = 0;
     }
 
-    // g_debug("options.autosave.enable = %lld", prefs_get_int_attribute_limited("options.autosave", "enable", 1, 0, 1));
+    // g_debug("options.autosave.enable = %d", prefs->getBool("/options/autosave/enable", true));
     // Is autosave enabled?
-    if( prefs_get_int_attribute_limited("options.autosave", "enable", 1, 0, 1) != 1 ){
+    if (!prefs->getBool("/options/autosave/enable", true)){
         autosave_timeout_id = 0;
     } else {
         // Turn on autosave
-        guint32 timeout = prefs_get_int_attribute("options.autosave", "interval", 10) * 60;
-        // g_debug("options.autosave.interval = %lld", prefs_get_int_attribute("options.autosave", "interval", 10));
+        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
@@ -472,16 +459,13 @@ inkscape_init (SPObject * object)
         g_assert_not_reached ();
     }
 
-    new (&inkscape->document_set) std::multiset<SPDocument *>();
+    new (&inkscape->document_set) std::map<SPDocument *, int>();
 
     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
@@ -489,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 */
@@ -504,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);
 
@@ -544,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)
 {
@@ -563,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*/)
 {
@@ -572,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.
      * */
@@ -583,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<SimpleEvent<Inkscape::Debug::Event::CORE> > tracker("crash");
     tracker.set<SimpleEvent<> >("emergency-save");
 
@@ -601,67 +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<SPDocument*,int>::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; i<sizeof(locations)/sizeof(*locations); i++) {
+                if (!locations[i]) continue; // It seems to be okay, but just in case
+                gchar * filename = g_build_filename(locations[i], c, NULL);
+                Inkscape::IO::dump_fopen_call(filename, "E");
+                file = Inkscape::IO::fopen_utf8name(filename, "w");
+                if (file) {
+                    g_snprintf (c, 1024, "%s", filename); // we want the complete path to be stored in c (for reporting purposes)
+                    break;
+                }
             }
+
+            // Save
             if (file) {
                 sp_repr_save_stream (repr->document(), file, SP_SVG_NS_URI);
                 savednames = g_slist_prepend (savednames, g_strdup (c));
                 fclose (file);
             } else {
-                failednames = g_slist_prepend (failednames, (doc->name) ? g_strdup (doc->name) : 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);
@@ -678,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");
@@ -733,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);
@@ -751,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)
@@ -769,29 +804,49 @@ 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 */
@@ -811,176 +866,38 @@ inkscape_get_instance()
         return inkscape;
 }
 
-gboolean inkscape_app_use_gui( Inkscape::Application const * app )
-{
-    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)
+gboolean inkscape_use_gui()
 {
-    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);
+    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;
         }
-
-        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;
-        }
-
-        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())) {
@@ -992,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())) {
@@ -1006,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)) {
@@ -1021,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())) {
@@ -1037,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));
 
@@ -1054,12 +955,6 @@ 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));
@@ -1078,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));
@@ -1118,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)) {
@@ -1152,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))
@@ -1270,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;
 }
 
 
@@ -1284,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;
 }
 
 
@@ -1321,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<SPDocument*,int>::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<SPDocument*,int>::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;
     }
@@ -1373,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);
     }
@@ -1414,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)
 {
@@ -1549,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);
 }
@@ -1592,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\;
@@ -1637,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 *
@@ -1662,8 +1452,6 @@ inkscape_get_all_desktops(std::list< SPDesktop* >& listbuf)
     }
 }
 
-
-
 /*
   Local Variables:
   mode:c++