diff --git a/src/inkscape.cpp b/src/inkscape.cpp
index ac2a64ed7f215fe7dcb57b29bd0fdee620c56800..586abd22b7056bb55dd701f678e54c50e6dc5267 100644 (file)
--- a/src/inkscape.cpp
+++ b/src/inkscape.cpp
-#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>
*
# include "config.h"
#endif
+#include <errno.h>
+#include <map>
#include "debug/simple-event.h"
#include "debug/event-tracker.h"
# include <shlobj.h>
#endif
-#include <signal.h>
-
+#include <cstring>
+#include <glib/gstdio.h>
+#include <glib.h>
+#include <glibmm/i18n.h>
#include <gtk/gtkmain.h>
#include <gtk/gtkmessagedialog.h>
-
-#include <glibmm/i18n.h>
-#include "helper/sp-marshal.h"
-#include "dialogs/debugdialog.h"
+#include <gtkmm/messagedialog.h>
+#include <signal.h>
+#include <string>
#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 "dialogs/input.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;
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;
- 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 {
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"
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<SPDocument*,int>::iterator iter = inkscape->document_set.begin();
+ iter != inkscape->document_set.end();
+ ++iter) {
+
+ SPDocument *doc = iter->first;
+
+ ++docnum;
+
+ 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)");
+
+ 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)
g_assert_not_reached ();
}
- inkscape->menus = sp_repr_read_mem (_(menus_skeleton), MENUS_SKELETON_SIZE, NULL);
+ new (&inkscape->document_set) std::map<SPDocument *, int>();
- inkscape->documents = NULL;
+ 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->trackalt = FALSE;
}
-
static void
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 */
inkscape->menus = NULL;
}
+ inkscape->document_set.~map();
+
G_OBJECT_CLASS (parent_class)->dispose (object);
gtk_main_quit ();
g_object_unref (G_OBJECT (inkscape));
}
+/* returns the mask of the keyboard modifier to map to Alt, zero if no mapping */
+/* Needs to be a guint because gdktypes.h does not define a 'no-modifier' value */
+guint
+inkscape_mapalt() {
+ return inkscape->mapalt;
+}
+
+/* Sets the keyboard modifer to map to Alt. Zero switches off mapping, as does '1', which is the default */
+void inkscape_mapalt(guint maskvalue)
+{
+ if(maskvalue<2 || maskvalue> 5 ){ /* MOD5 is the highest defined in gdktypes.h */
+ inkscape->mapalt=0;
+ }else{
+ inkscape->mapalt=(GDK_MOD1_MASK << (maskvalue-1));
+ }
+}
+
+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)
+inkscape_activate_desktop_private (Inkscape::Application */*inkscape*/, SPDesktop *desktop)
{
desktop->set_active (true);
}
static void
-inkscape_deactivate_desktop_private (Inkscape::Application *inkscape, SPDesktop *desktop)
+inkscape_deactivate_desktop_private (Inkscape::Application */*inkscape*/, SPDesktop *desktop)
{
desktop->set_active (false);
}
static void
-inkscape_crash_handler (int signum)
+inkscape_crash_handler (int /*signum*/)
{
using Inkscape::Debug::SimpleEvent;
using Inkscape::Debug::EventTracker;
static gint recursion = FALSE;
- /*
+ /*
* reset all signal handlers: any further crashes should just be allowed
* to crash normally.
* */
#ifndef WIN32
signal (SIGBUS, bus_handler );
#endif
-
+
/* Stop bizarre loops */
if (recursion) {
abort ();
gint count = 0;
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);
- if (repr->attribute("sodipodi:modified")) {
+ if (doc->isModifiedSinceSave()) {
const gchar *docname, *d0, *d;
gchar n[64], c[1024];
FILE *file;
if (!docname || !*docname) docname = "emergency";
// try saving to the profile location
- g_snprintf (c, 1024, "%.256s.%s.%d", docname, sptstr, count);
+ g_snprintf (c, 1024, "%.256s.%s.%d.svg", docname, sptstr, count);
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
- g_snprintf (c, 1024, "/tmp/inkscape-%.256s.%s.%d", docname, sptstr, count);
+ g_snprintf (c, 1024, "/tmp/inkscape-%.256s.%s.%d.svg", 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);
+ 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 (sp_repr_document (repr), file, SP_SVG_NS_URI);
+ sp_repr_save_stream (repr->document(), 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->name) ? g_strdup (doc->name) : g_strdup (_("Untitled document")));
}
count++;
}
}
}
- 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");
}
+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)
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);
+ 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_get_int_attribute("dialogs.debug", "redirect", DEFAULT_LOG_REDIRECT))
+ if (use_gui == TRUE && prefs->getBool("/dialogs/debug/redirect", DEFAULT_LOG_REDIRECT))
+ {
+ Inkscape::UI::Dialog::DebugDialog::getInstance()->captureLogMessages();
+ }
+
+ /* Check for global remapping of Alt key */
+ if (use_gui)
{
- Inkscape::UI::Dialogs::DebugDialog::getInstance()->captureLogMessages();
+ 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;
}
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 = sp_repr_document_root (doc);
- 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;
-}
-
/**
* 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) {
- return NULL;
- }
-
- Inkscape::XML::Node *repr = sp_repr_document_root (Inkscape::Preferences::get());
- 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)
{
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));
}
if (!Inkscape::NSApplication::Application::getNewGui())
{
- g_assert (!g_slist_find (inkscape->documents, document));
- inkscape->documents = g_slist_append (inkscape->documents, 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 ++;
+ }
+ }
+ }
}
else
{
}
-
-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);
+ g_return_val_if_fail (document != NULL, false);
if (!Inkscape::NSApplication::Application::getNewGui())
{
- g_assert (g_slist_find (inkscape->documents, document));
- inkscape->documents = g_slist_remove (inkscape->documents, document);
+ 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 *
# 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;
- }
- }
- } 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)
{
* saves the preferences if appropriate, and quits.
*/
void
-inkscape_exit (Inkscape::Application *inkscape)
+inkscape_exit (Inkscape::Application */*inkscape*/)
{
g_assert (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);
}
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\;
}
*/
}
+
+ 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);
+ }
+
+ 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 *
inkscape_get_menus (Inkscape::Application * inkscape)
{
- Inkscape::XML::Node *repr = sp_repr_document_root (inkscape->menus);
+ Inkscape::XML::Node *repr = inkscape->menus->root();
g_assert (!(strcmp (repr->name(), "inkscape")));
return repr->firstChild();
}
}
}
-
-
/*
Local Variables:
mode:c++