Code

Refactored multiple methods to single data-driven one.
[inkscape.git] / src / inkscape.cpp
index dca23d5396fd8e294e3082b41d3ae4d31152f465..586abd22b7056bb55dd701f678e54c50e6dc5267 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,6 +15,7 @@
 # include "config.h"
 #endif
 
+#include <errno.h>
 
 #include <map>
 #include "debug/simple-event.h"
@@ -37,38 +36,34 @@ 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 "dialogs/input.h"
 #include "application/application.h"
 #include "application/editor.h"
-
-
-#include "document.h"
 #include "desktop.h"
 #include "desktop-handles.h"
-#include "selection.h"
+#include "dialogs/input.h"
+#include "document.h"
 #include "event-context.h"
-#include "inkscape-private.h"
-#include "xml/repr.h"
-#include "preferences.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;
 
@@ -117,6 +112,7 @@ struct Inkscape::Application {
     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 {
@@ -145,9 +141,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;
+#endif
 
-#define INKSCAPE_PROFILE_DIR "Inkscape"
+#define INKSCAPE_PROFILE_DIR "inkscape"
+#define INKSCAPE_PROFILE_DIR_047DEV "Inkscape"
+#define INKSCAPE_LEGACY_PROFILE_DIR ".inkscape"
 #define MENUS_FILE "menus.xml"
 
 
@@ -302,7 +302,7 @@ static gint inkscape_autosave(gpointer)
 
     Glib::ustring autosave_dir;
     {
-        Glib::ustring tmp = prefs->getString("options.autosave", "path");
+        Glib::ustring tmp = prefs->getString("/options/autosave/path");
         if (!tmp.empty()) {
             autosave_dir = tmp;
         } else {
@@ -321,13 +321,13 @@ static gint inkscape_autosave(gpointer)
     gchar sptstr[256];
     strftime(sptstr, 256, "%Y_%m_%d_%H_%M_%S", sptm);
 
-    gint autosave_max = prefs->getInt("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 (std::map<SPDocument*,int>::iterator iter = inkscape->document_set.begin(); 
-          iter != inkscape->document_set.end(); 
+    for (std::map<SPDocument*,int>::iterator iter = inkscape->document_set.begin();
+          iter != inkscape->document_set.end();
           ++iter) {
 
         SPDocument *doc = iter->first;
@@ -437,14 +437,14 @@ void inkscape_autosave_init()
         autosave_timeout_id = 0;
     }
 
-    // g_debug("options.autosave.enable = %d", prefs->getBool("options.autosave", "enable", true));
+    // g_debug("options.autosave.enable = %d", prefs->getBool("/options/autosave/enable", true));
     // Is autosave enabled?
-    if (!prefs->getBool("options.autosave", "enable", true)){
+    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));
+        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
@@ -466,12 +466,10 @@ inkscape_init (SPObject * object)
     new (&inkscape->document_set) std::map<SPDocument *, int>();
 
     inkscape->menus = sp_repr_read_mem (_(menus_skeleton), MENUS_SKELETON_SIZE, NULL);
-
     inkscape->desktops = NULL;
-
     inkscape->dialogs_toggle = TRUE;
-
-    inkscape->mapalt=GDK_MOD1_MASK;
+    inkscape->mapalt = GDK_MOD1_MASK;
+    inkscape->trackalt = FALSE;
 }
 
 static void
@@ -529,6 +527,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)
 {
@@ -588,8 +597,8 @@ inkscape_crash_handler (int /*signum*/)
     gint count = 0;
     GSList *savednames = NULL;
     GSList *failednames = NULL;
-    for (std::map<SPDocument*,int>::iterator iter = inkscape->document_set.begin(); 
-          iter != inkscape->document_set.end(); 
+    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;
@@ -625,6 +634,7 @@ inkscape_crash_handler (int /*signum*/)
             gchar * location = homedir_path(c);
             Inkscape::IO::dump_fopen_call(location, "E");
             file = Inkscape::IO::fopen_utf8name(location, "w");
+            g_snprintf (c, 1024, "%s", location); // we want the complete path to be stored in c (for reporting purposes)
             g_free(location);
             if (!file) {
                 // try saving to /tmp
@@ -634,9 +644,14 @@ inkscape_crash_handler (int /*signum*/)
             }
             if (!file) {
                 // try saving to the current directory
+                gchar *curdir = g_get_current_dir();
                 g_snprintf (c, 1024, "inkscape-%.256s.%s.%d.svg", docname, sptstr, count);
                 Inkscape::IO::dump_fopen_call(c, "F");
                 file = Inkscape::IO::fopen_utf8name(c, "w");
+                // store the complete path in c so that it can be reported later
+                gchar * location = g_build_filename(curdir, c, NULL);
+                g_snprintf (c, 1024, "%s", location);
+                g_free(location);
             }
             if (file) {
                 sp_repr_save_stream (repr->document(), file, SP_SVG_NS_URI);
@@ -664,7 +679,8 @@ inkscape_crash_handler (int /*signum*/)
         }
     }
 
-    Inkscape::Preferences::unload();
+    // 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");
@@ -737,6 +753,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)
@@ -755,31 +793,49 @@ inkscape_application_init (const gchar *argv0, gboolean use_gui)
     inkscape->use_gui = use_gui;
     inkscape->argv0 = g_strdup(argv0);
 
-    /* Load the preferences and menus; Later menu layout should be merged into prefs */
-    Inkscape::Preferences::use_gui = use_gui;
-    Inkscape::Preferences::load();
+    /* Load the preferences and menus */
     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
-    inkscape_load_menus(inkscape);
-    sp_input_load_from_preferences();
+    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);
+        sp_input_load_from_preferences();
+    }
+
+    /* 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->getBool("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->getInt("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 */
@@ -810,27 +866,21 @@ gboolean inkscape_app_use_gui( Inkscape::Application const * app )
  */
 bool inkscape_load_menus (Inkscape::Application */*inkscape*/)
 {
+    // TODO fix that fn is being leaked
     gchar *fn = profile_path(MENUS_FILE);
-    gchar *menus_xml = NULL; gsize len = 0;
+    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;
+        if (INKSCAPE->menus) {
+            return true;
+        }
     }
     INKSCAPE->menus = sp_repr_read_mem(menus_skeleton, MENUS_SKELETON_SIZE, NULL);
-    if (INKSCAPE->menus) return true;
-    return false;
-}
-
-/**
- * @deprecated Use the Preferences class instead, and try not to use _getNode
- */
-Inkscape::XML::Node *inkscape_get_repr(Inkscape::Application */*inkscape*/, const gchar *key)
-{
-    Inkscape::Preferences *ps = Inkscape::Preferences::get();
-    return ps->_getNode(key);
+    return (INKSCAPE->menus != 0);
 }
 
 
@@ -1186,8 +1236,8 @@ inkscape_add_document (SPDocument *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(); 
+            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
@@ -1211,8 +1261,8 @@ inkscape_remove_document (SPDocument *document)
 
     if (!Inkscape::NSApplication::Application::getNewGui())
     {
-        for (std::map<SPDocument*,int>::iterator iter = inkscape->document_set.begin(); 
-                  iter != inkscape->document_set.end(); 
+        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
@@ -1339,7 +1389,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\;
@@ -1384,13 +1442,57 @@ profile_path(const char *filename)
                 }
                 */
             }
+
+            if (prefdir) {
+                prefdir = g_build_filename(prefdir, INKSCAPE_PROFILE_DIR, NULL);
+            }
         }
 #endif
         if (!prefdir) {
-            prefdir = homedir_path(".config");
+            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);
+            }
+
+            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 *
@@ -1409,8 +1511,6 @@ inkscape_get_all_desktops(std::list< SPDesktop* >& listbuf)
     }
 }
 
-
-
 /*
   Local Variables:
   mode:c++