Code

get rid of sp_repr_document_root and (commented) sp_repr_duplicate
[inkscape.git] / src / inkscape.cpp
1 #define __INKSCAPE_C__
3 /*
4  * Interface to main application
5  *
6  * Authors:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *   bulia byak <buliabyak@users.sf.net>
9  *
10  * Copyright (C) 1999-2005 authors
11  * g++ port Copyright (C) 2003 Nathan Hurst
12  *
13  * Released under GNU GPL, read the file 'COPYING' for more information
14  */
16 #ifdef HAVE_CONFIG_H
17 # include "config.h"
18 #endif
21 #include "debug/simple-event.h"
22 #include "debug/event-tracker.h"
24 #ifndef WIN32
25 # define HAS_PROC_SELF_EXE  //to get path of executable
26 #else
28 // For now to get at is_os_wide().
29 # include "extension/internal/win32.h"
30 using Inkscape::Extension::Internal::PrintWin32;
32 #define _WIN32_IE 0x0400
33 //#define HAS_SHGetSpecialFolderPath
34 #define HAS_SHGetSpecialFolderLocation
35 #define HAS_GetModuleFileName
36 # include <shlobj.h>
37 #endif
39 #include <signal.h>
41 #include <gtk/gtkmain.h>
42 #include <gtk/gtkmessagedialog.h>
44 #include <glibmm/i18n.h>
45 #include "helper/sp-marshal.h"
46 #include "dialogs/debugdialog.h"
47 #include "application/application.h"
48 #include "application/editor.h"
49 #include "preferences.h"
52 #include "document.h"
53 #include "desktop.h"
54 #include "desktop-handles.h"
55 #include "selection.h"
56 #include "event-context.h"
57 #include "inkscape-private.h"
58 #include "prefs-utils.h"
59 #include "xml/repr.h"
60 #include "io/sys.h"
62 #include "extension/init.h"
64 static Inkscape::Application *inkscape = NULL;
66 /* Backbones of configuration xml data */
67 #include "menus-skeleton.h"
69 enum {
70     MODIFY_SELECTION, // global: one of selections modified
71     CHANGE_SELECTION, // global: one of selections changed
72     CHANGE_SUBSELECTION, // global: one of subselections (text selection, gradient handle, etc) changed
73     SET_SELECTION, // global: one of selections set
74     SET_EVENTCONTEXT, // tool switched
75     ACTIVATE_DESKTOP, // some desktop got focus
76     DEACTIVATE_DESKTOP, // some desktop lost focus
77     SHUTDOWN_SIGNAL, // inkscape is quitting
78     DIALOGS_HIDE, // user pressed F12
79     DIALOGS_UNHIDE, // user pressed F12
80     EXTERNAL_CHANGE, // a document was changed by some external means (undo or XML editor); this
81                      // may not be reflected by a selection change and thus needs a separate signal
82     LAST_SIGNAL
83 };
85 #define DESKTOP_IS_ACTIVE(d) ((d) == inkscape->desktops->data)
88 /*################################
89 # FORWARD DECLARATIONS
90 ################################*/
92 gboolean inkscape_app_use_gui( Inkscape::Application const * app );
94 static void inkscape_class_init (Inkscape::ApplicationClass *klass);
95 static void inkscape_init (SPObject *object);
96 static void inkscape_dispose (GObject *object);
98 static void inkscape_activate_desktop_private (Inkscape::Application *inkscape, SPDesktop *desktop);
99 static void inkscape_deactivate_desktop_private (Inkscape::Application *inkscape, SPDesktop *desktop);
101 static bool inkscape_init_config (Inkscape::XML::Document *doc, const gchar *config_name, const gchar *skeleton,
102                                   unsigned int skel_size,
103                                   const gchar *e_mkdir,
104                                   const gchar *e_notdir,
105                                   const gchar *e_ccf,
106                                   const gchar *e_cwf,
107                                   const gchar *warn);
109 struct Inkscape::Application {
110     GObject object;
111     Inkscape::XML::Document *menus;
112     GSList *documents;
113     GSList *desktops;
114     gchar *argv0;
115     gboolean dialogs_toggle;
116     gboolean use_gui;         // may want to consider a virtual function
117                               // for overriding things like the warning dlg's
118 };
120 struct Inkscape::ApplicationClass {
121     GObjectClass object_class;
123     /* Signals */
124     void (* change_selection) (Inkscape::Application * inkscape, Inkscape::Selection * selection);
125     void (* change_subselection) (Inkscape::Application * inkscape, SPDesktop *desktop);
126     void (* modify_selection) (Inkscape::Application * inkscape, Inkscape::Selection * selection, guint flags);
127     void (* set_selection) (Inkscape::Application * inkscape, Inkscape::Selection * selection);
128     void (* set_eventcontext) (Inkscape::Application * inkscape, SPEventContext * eventcontext);
129     void (* activate_desktop) (Inkscape::Application * inkscape, SPDesktop * desktop);
130     void (* deactivate_desktop) (Inkscape::Application * inkscape, SPDesktop * desktop);
131     void (* destroy_document) (Inkscape::Application *inkscape, SPDocument *doc);
132     void (* color_set) (Inkscape::Application *inkscape, SPColor *color, double opacity);
133     void (* shut_down) (Inkscape::Application *inkscape);
134     void (* dialogs_hide) (Inkscape::Application *inkscape);
135     void (* dialogs_unhide) (Inkscape::Application *inkscape);
136     void (* external_change) (Inkscape::Application *inkscape);
137 };
139 static GObjectClass * parent_class;
140 static guint inkscape_signals[LAST_SIGNAL] = {0};
142 static void (* segv_handler) (int) = SIG_DFL;
143 static void (* abrt_handler) (int) = SIG_DFL;
144 static void (* fpe_handler)  (int) = SIG_DFL;
145 static void (* ill_handler)  (int) = SIG_DFL;
146 static void (* bus_handler)  (int) = SIG_DFL;
148 #ifdef WIN32
149 #define INKSCAPE_PROFILE_DIR "Inkscape"
150 #else
151 #define INKSCAPE_PROFILE_DIR ".inkscape"
152 #endif
154 #define MENUS_FILE "menus.xml"
157 /**
158  *  Retrieves the GType for the Inkscape Application object.
159  */
160 GType
161 inkscape_get_type (void)
163     static GType type = 0;
164     if (!type) {
165         GTypeInfo info = {
166             sizeof (Inkscape::ApplicationClass),
167             NULL, NULL,
168             (GClassInitFunc) inkscape_class_init,
169             NULL, NULL,
170             sizeof (Inkscape::Application),
171             4,
172             (GInstanceInitFunc) inkscape_init,
173             NULL
174         };
175         type = g_type_register_static (G_TYPE_OBJECT, "Inkscape_Application", &info, (GTypeFlags)0);
176     }
177     return type;
181 /**
182  *  Initializes the inkscape class, registering all of its signal handlers
183  *  and virtual functions
184  */
185 static void
186 inkscape_class_init (Inkscape::ApplicationClass * klass)
188     GObjectClass * object_class;
190     object_class = (GObjectClass *) klass;
192     parent_class = (GObjectClass *)g_type_class_peek_parent (klass);
194     inkscape_signals[MODIFY_SELECTION] = g_signal_new ("modify_selection",
195                                G_TYPE_FROM_CLASS (klass),
196                                G_SIGNAL_RUN_FIRST,
197                                G_STRUCT_OFFSET (Inkscape::ApplicationClass, modify_selection),
198                                NULL, NULL,
199                                sp_marshal_NONE__POINTER_UINT,
200                                G_TYPE_NONE, 2,
201                                G_TYPE_POINTER, G_TYPE_UINT);
202     inkscape_signals[CHANGE_SELECTION] = g_signal_new ("change_selection",
203                                G_TYPE_FROM_CLASS (klass),
204                                G_SIGNAL_RUN_FIRST,
205                                G_STRUCT_OFFSET (Inkscape::ApplicationClass, change_selection),
206                                NULL, NULL,
207                                sp_marshal_NONE__POINTER,
208                                G_TYPE_NONE, 1,
209                                G_TYPE_POINTER);
210     inkscape_signals[CHANGE_SUBSELECTION] = g_signal_new ("change_subselection",
211                                G_TYPE_FROM_CLASS (klass),
212                                G_SIGNAL_RUN_FIRST,
213                                G_STRUCT_OFFSET (Inkscape::ApplicationClass, change_subselection),
214                                NULL, NULL,
215                                sp_marshal_NONE__POINTER,
216                                G_TYPE_NONE, 1,
217                                G_TYPE_POINTER);
218     inkscape_signals[SET_SELECTION] =    g_signal_new ("set_selection",
219                                G_TYPE_FROM_CLASS (klass),
220                                G_SIGNAL_RUN_FIRST,
221                                G_STRUCT_OFFSET (Inkscape::ApplicationClass, set_selection),
222                                NULL, NULL,
223                                sp_marshal_NONE__POINTER,
224                                G_TYPE_NONE, 1,
225                                G_TYPE_POINTER);
226     inkscape_signals[SET_EVENTCONTEXT] = g_signal_new ("set_eventcontext",
227                                G_TYPE_FROM_CLASS (klass),
228                                G_SIGNAL_RUN_FIRST,
229                                G_STRUCT_OFFSET (Inkscape::ApplicationClass, set_eventcontext),
230                                NULL, NULL,
231                                sp_marshal_NONE__POINTER,
232                                G_TYPE_NONE, 1,
233                                G_TYPE_POINTER);
234     inkscape_signals[ACTIVATE_DESKTOP] = g_signal_new ("activate_desktop",
235                                G_TYPE_FROM_CLASS (klass),
236                                G_SIGNAL_RUN_FIRST,
237                                G_STRUCT_OFFSET (Inkscape::ApplicationClass, activate_desktop),
238                                NULL, NULL,
239                                sp_marshal_NONE__POINTER,
240                                G_TYPE_NONE, 1,
241                                G_TYPE_POINTER);
242     inkscape_signals[DEACTIVATE_DESKTOP] = g_signal_new ("deactivate_desktop",
243                                G_TYPE_FROM_CLASS (klass),
244                                G_SIGNAL_RUN_FIRST,
245                                G_STRUCT_OFFSET (Inkscape::ApplicationClass, deactivate_desktop),
246                                NULL, NULL,
247                                sp_marshal_NONE__POINTER,
248                                G_TYPE_NONE, 1,
249                                G_TYPE_POINTER);
250     inkscape_signals[SHUTDOWN_SIGNAL] =        g_signal_new ("shut_down",
251                                G_TYPE_FROM_CLASS (klass),
252                                G_SIGNAL_RUN_FIRST,
253                                G_STRUCT_OFFSET (Inkscape::ApplicationClass, shut_down),
254                                NULL, NULL,
255                                g_cclosure_marshal_VOID__VOID,
256                                G_TYPE_NONE, 0);
257     inkscape_signals[DIALOGS_HIDE] =        g_signal_new ("dialogs_hide",
258                                G_TYPE_FROM_CLASS (klass),
259                                G_SIGNAL_RUN_FIRST,
260                                G_STRUCT_OFFSET (Inkscape::ApplicationClass, dialogs_hide),
261                                NULL, NULL,
262                                g_cclosure_marshal_VOID__VOID,
263                                G_TYPE_NONE, 0);
264     inkscape_signals[DIALOGS_UNHIDE] =        g_signal_new ("dialogs_unhide",
265                                G_TYPE_FROM_CLASS (klass),
266                                G_SIGNAL_RUN_FIRST,
267                                G_STRUCT_OFFSET (Inkscape::ApplicationClass, dialogs_unhide),
268                                NULL, NULL,
269                                g_cclosure_marshal_VOID__VOID,
270                                G_TYPE_NONE, 0);
271     inkscape_signals[EXTERNAL_CHANGE] =   g_signal_new ("external_change",
272                                G_TYPE_FROM_CLASS (klass),
273                                G_SIGNAL_RUN_FIRST,
274                                G_STRUCT_OFFSET (Inkscape::ApplicationClass, external_change),
275                                NULL, NULL,
276                                g_cclosure_marshal_VOID__VOID,
277                                G_TYPE_NONE, 0);
279     object_class->dispose = inkscape_dispose;
281     klass->activate_desktop = inkscape_activate_desktop_private;
282     klass->deactivate_desktop = inkscape_deactivate_desktop_private;
286 static void
287 inkscape_init (SPObject * object)
289     if (!inkscape) {
290         inkscape = (Inkscape::Application *) object;
291     } else {
292         g_assert_not_reached ();
293     }
295     inkscape->menus = sp_repr_read_mem (_(menus_skeleton), MENUS_SKELETON_SIZE, NULL);
297     inkscape->documents = NULL;
298     inkscape->desktops = NULL;
300     inkscape->dialogs_toggle = TRUE;
304 static void
305 inkscape_dispose (GObject *object)
307     Inkscape::Application *inkscape = (Inkscape::Application *) object;
309     while (inkscape->documents) {
310         // we don't otherwise unref, so why here?
311         sp_document_unref((SPDocument *)inkscape->documents->data);
312     }
314     g_assert (!inkscape->desktops);
316     Inkscape::Preferences::save();
318     if (inkscape->menus) {
319         /* fixme: This is not the best place */
320         Inkscape::GC::release(inkscape->menus);
321         inkscape->menus = NULL;
322     }
324     G_OBJECT_CLASS (parent_class)->dispose (object);
326     gtk_main_quit ();
330 void
331 inkscape_ref (void)
333     if (inkscape)
334         g_object_ref (G_OBJECT (inkscape));
338 void
339 inkscape_unref (void)
341     if (inkscape)
342         g_object_unref (G_OBJECT (inkscape));
346 static void
347 inkscape_activate_desktop_private (Inkscape::Application *inkscape, SPDesktop *desktop)
349     desktop->set_active (true);
353 static void
354 inkscape_deactivate_desktop_private (Inkscape::Application *inkscape, SPDesktop *desktop)
356     desktop->set_active (false);
360 /* fixme: This is EVIL, and belongs to main after all */
362 #define SP_INDENT 8
365 static void
366 inkscape_crash_handler (int signum)
368     using Inkscape::Debug::SimpleEvent;
369     using Inkscape::Debug::EventTracker;
370     using Inkscape::Debug::Logger;
372     static gint recursion = FALSE;
374     /* 
375      * reset all signal handlers: any further crashes should just be allowed
376      * to crash normally.
377      * */
378     signal (SIGSEGV, segv_handler );
379     signal (SIGABRT, abrt_handler );
380     signal (SIGFPE,  fpe_handler  );
381     signal (SIGILL,  ill_handler  );
382 #ifndef WIN32
383     signal (SIGBUS,  bus_handler  );
384 #endif
385     
386     /* Stop bizarre loops */
387     if (recursion) {
388         abort ();
389     }
390     recursion = TRUE;
392     EventTracker<SimpleEvent<Inkscape::Debug::Event::CORE> > tracker("crash");
393     tracker.set<SimpleEvent<> >("emergency-save");
395     fprintf(stderr, "\nEmergency save activated!\n");
397     time_t sptime = time (NULL);
398     struct tm *sptm = localtime (&sptime);
399     gchar sptstr[256];
400     strftime (sptstr, 256, "%Y_%m_%d_%H_%M_%S", sptm);
402     gint count = 0;
403     GSList *savednames = NULL;
404     GSList *failednames = NULL;
405     for (GSList *l = inkscape->documents; l != NULL; l = l->next) {
406         SPDocument *doc;
407         Inkscape::XML::Node *repr;
408         doc = (SPDocument *) l->data;
409         repr = sp_document_repr_root (doc);
410         if (repr->attribute("sodipodi:modified")) {
411             const gchar *docname, *d0, *d;
412             gchar n[64], c[1024];
413             FILE *file;
415             /* originally, the document name was retrieved from
416              * the sodipod:docname attribute */
417             docname = doc->name;
418             if (docname) {
419                 /* fixme: Quick hack to remove emergency file suffix */
420                 d0 = strrchr ((char*)docname, '.');
421                 if (d0 && (d0 > docname)) {
422                     d0 = strrchr ((char*)(d0 - 1), '.');
423                     if (d0 && (d0 > docname)) {
424                         d = d0;
425                         while (isdigit (*d) || (*d == '.') || (*d == '_')) d += 1;
426                         if (*d) {
427                             memcpy (n, docname, MIN (d0 - docname - 1, 64));
428                             n[63] = '\0';
429                             docname = n;
430                         }
431                     }
432                 }
433             }
435             if (!docname || !*docname) docname = "emergency";
436             // try saving to the profile location
437             g_snprintf (c, 1024, "%.256s.%s.%d", docname, sptstr, count);
438             gchar * location = homedir_path(c);
439             Inkscape::IO::dump_fopen_call(location, "E");
440             file = Inkscape::IO::fopen_utf8name(location, "w");
441             g_free(location);
442             if (!file) {
443                 // try saving to /tmp
444                 g_snprintf (c, 1024, "/tmp/inkscape-%.256s.%s.%d", docname, sptstr, count);
445                 Inkscape::IO::dump_fopen_call(c, "G");
446                 file = Inkscape::IO::fopen_utf8name(c, "w");
447             }
448             if (!file) {
449                 // try saving to the current directory
450                 g_snprintf (c, 1024, "inkscape-%.256s.%s.%d", docname, sptstr, count);
451                 Inkscape::IO::dump_fopen_call(c, "F");
452                 file = Inkscape::IO::fopen_utf8name(c, "w");
453             }
454             if (file) {
455                 sp_repr_save_stream (repr->document(), file, SP_SVG_NS_URI);
456                 savednames = g_slist_prepend (savednames, g_strdup (c));
457                 fclose (file);
458             } else {
459                 docname = repr->attribute("sodipodi:docname");
460                 failednames = g_slist_prepend (failednames, (docname) ? g_strdup (docname) : g_strdup (_("Untitled document")));
461             }
462             count++;
463         }
464     }
466     savednames = g_slist_reverse (savednames);
467     failednames = g_slist_reverse (failednames);
468     if (savednames) {
469         fprintf (stderr, "\nEmergency save document locations:\n");
470         for (GSList *l = savednames; l != NULL; l = l->next) {
471             fprintf (stderr, "  %s\n", (gchar *) l->data);
472         }
473     }
474     if (failednames) {
475         fprintf (stderr, "\nFailed to do emergency save for documents:\n");
476         for (GSList *l = failednames; l != NULL; l = l->next) {
477             fprintf (stderr, "  %s\n", (gchar *) l->data);
478         }
479     }
481     Inkscape::Preferences::save();
483     fprintf (stderr, "Emergency save completed. Inkscape will close now.\n");
484     fprintf (stderr, "If you can reproduce this crash, please file a bug at www.inkscape.org\n");
485     fprintf (stderr, "with a detailed description of the steps leading to the crash, so we can fix it.\n");
487     /* Show nice dialog box */
489     char const *istr = _("Inkscape encountered an internal error and will close now.\n");
490     char const *sstr = _("Automatic backups of unsaved documents were done to the following locations:\n");
491     char const *fstr = _("Automatic backup of the following documents failed:\n");
492     gint nllen = strlen ("\n");
493     gint len = strlen (istr) + strlen (sstr) + strlen (fstr);
494     for (GSList *l = savednames; l != NULL; l = l->next) {
495         len = len + SP_INDENT + strlen ((gchar *) l->data) + nllen;
496     }
497     for (GSList *l = failednames; l != NULL; l = l->next) {
498         len = len + SP_INDENT + strlen ((gchar *) l->data) + nllen;
499     }
500     len += 1;
501     gchar *b = g_new (gchar, len);
502     gint pos = 0;
503     len = strlen (istr);
504     memcpy (b + pos, istr, len);
505     pos += len;
506     if (savednames) {
507         len = strlen (sstr);
508         memcpy (b + pos, sstr, len);
509         pos += len;
510         for (GSList *l = savednames; l != NULL; l = l->next) {
511             memset (b + pos, ' ', SP_INDENT);
512             pos += SP_INDENT;
513             len = strlen ((gchar *) l->data);
514             memcpy (b + pos, l->data, len);
515             pos += len;
516             memcpy (b + pos, "\n", nllen);
517             pos += nllen;
518         }
519     }
520     if (failednames) {
521         len = strlen (fstr);
522         memcpy (b + pos, fstr, len);
523         pos += len;
524         for (GSList *l = failednames; l != NULL; l = l->next) {
525             memset (b + pos, ' ', SP_INDENT);
526             pos += SP_INDENT;
527             len = strlen ((gchar *) l->data);
528             memcpy (b + pos, l->data, len);
529             pos += len;
530             memcpy (b + pos, "\n", nllen);
531             pos += nllen;
532         }
533     }
534     *(b + pos) = '\0';
536     if ( inkscape_get_instance() && inkscape_app_use_gui( inkscape_get_instance() ) ) {
537         GtkWidget *msgbox = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", b);
538         gtk_dialog_run (GTK_DIALOG (msgbox));
539         gtk_widget_destroy (msgbox);
540     }
541     else
542     {
543         g_message( "Error: %s", b );
544     }
545     g_free (b);
547     tracker.clear();
548     Logger::shutdown();
550     /* on exit, allow restored signal handler to take over and crash us */
555 void
556 inkscape_application_init (const gchar *argv0, gboolean use_gui)
558     inkscape = (Inkscape::Application *)g_object_new (SP_TYPE_INKSCAPE, NULL);
559     /* fixme: load application defaults */
561     segv_handler = signal (SIGSEGV, inkscape_crash_handler);
562     abrt_handler = signal (SIGABRT, inkscape_crash_handler);
563     fpe_handler  = signal (SIGFPE,  inkscape_crash_handler);
564     ill_handler  = signal (SIGILL,  inkscape_crash_handler);
565 #ifndef WIN32
566     bus_handler  = signal (SIGBUS,  inkscape_crash_handler);
567 #endif
569     inkscape->use_gui = use_gui;
570     inkscape->argv0 = g_strdup(argv0);
572     /* Attempt to load the preferences, and set the save_preferences flag to TRUE
573        if we could, or FALSE if we couldn't */
574     Inkscape::Preferences::load();
575     inkscape_load_menus(inkscape);
577     /* DebugDialog redirection.  On Linux, default to OFF, on Win32, default to ON.
578          * Use only if use_gui is enabled 
579          */
580 #ifdef WIN32
581 #define DEFAULT_LOG_REDIRECT true
582 #else
583 #define DEFAULT_LOG_REDIRECT false
584 #endif
586     if (use_gui == TRUE && prefs_get_int_attribute("dialogs.debug", "redirect", DEFAULT_LOG_REDIRECT))
587     {
588                 Inkscape::UI::Dialogs::DebugDialog::getInstance()->captureLogMessages();
589     }
591     /* Initialize the extensions */
592     Inkscape::Extension::init();
594     return;
597 /**
598  *  Returns the current Inkscape::Application global object
599  */
600 Inkscape::Application *
601 inkscape_get_instance()
603         return inkscape;
606 gboolean inkscape_app_use_gui( Inkscape::Application const * app )
608     return app->use_gui;
611 /**
612  * Preference management
613  * We use '.' as separator
614  *
615  * Returns TRUE if the config file was successfully loaded, FALSE if not.
616  */
617 bool
618 inkscape_load_config (const gchar *filename, Inkscape::XML::Document *config, const gchar *skeleton,
619                       unsigned int skel_size, const gchar *e_notreg, const gchar *e_notxml,
620                       const gchar *e_notsp, const gchar *warn)
622     gchar *fn = profile_path(filename);
623     if (!Inkscape::IO::file_test(fn, G_FILE_TEST_EXISTS)) {
624         bool result;
625         /* No such file */
626         result = inkscape_init_config (config, filename, skeleton,
627                                        skel_size,
628                                        _("Cannot create directory %s.\n%s"),
629                                        _("%s is not a valid directory.\n%s"),
630                                        _("Cannot create file %s.\n%s"),
631                                        _("Cannot write file %s.\n%s"),
632                                        _("Although Inkscape will run, it will use default settings,\n"
633                                          "and any changes made in preferences will not be saved."));
634         g_free (fn);
635         return result;
636     }
638     if (!Inkscape::IO::file_test(fn, G_FILE_TEST_IS_REGULAR)) {
639         /* Not a regular file */
640         gchar *safeFn = Inkscape::IO::sanitizeString(fn);
641         GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_notreg, safeFn, warn);
642         gtk_dialog_run (GTK_DIALOG (w));
643         gtk_widget_destroy (w);
644         g_free(safeFn);
645         g_free (fn);
646         return false;
647     }
649     Inkscape::XML::Document *doc = sp_repr_read_file (fn, NULL);
650     if (doc == NULL) {
651         /* Not an valid xml file */
652         gchar *safeFn = Inkscape::IO::sanitizeString(fn);
653         GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_notxml, safeFn, warn);
654         gtk_dialog_run (GTK_DIALOG (w));
655         gtk_widget_destroy (w);
656         g_free(safeFn);
657         g_free (fn);
658         return false;
659     }
661     Inkscape::XML::Node *root = doc->root();
662     if (strcmp (root->name(), "inkscape")) {
663         gchar *safeFn = Inkscape::IO::sanitizeString(fn);
664         GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_notsp, safeFn, warn);
665         gtk_dialog_run (GTK_DIALOG (w));
666         gtk_widget_destroy (w);
667         Inkscape::GC::release(doc);
668         g_free(safeFn);
669         g_free (fn);
670         return false;
671     }
673     /** \todo this is a hack, need to figure out how to get
674      *        a reasonable merge working with the menus.xml file */
675     if (skel_size == MENUS_SKELETON_SIZE) {
676         if (INKSCAPE)
677             INKSCAPE->menus = doc;
678         doc = config;
679     } else {
680         config->root()->mergeFrom(doc->root(), "id");
681     }
683     Inkscape::GC::release(doc);
684     g_free (fn);
685     return true;
688 /**
689  *  Menus management
690  *
691  */
692 bool
693 inkscape_load_menus (Inkscape::Application *inkscape)
695     gchar *fn = profile_path(MENUS_FILE);
696     bool retval = false;
697     if (Inkscape::IO::file_test(fn, G_FILE_TEST_EXISTS)) {
698         retval = inkscape_load_config (MENUS_FILE,
699                                  inkscape->menus,
700                                  menus_skeleton,
701                                  MENUS_SKELETON_SIZE,
702                                  _("%s is not a regular file.\n%s"),
703                                  _("%s not a valid XML file, or\n"
704                                    "you don't have read permissions on it.\n%s"),
705                                  _("%s is not a valid menus file.\n%s"),
706                                  _("Inkscape will run with default menus.\n"
707                                    "New menus will not be saved."));
708     } else {
709         INKSCAPE->menus = sp_repr_read_mem(menus_skeleton, MENUS_SKELETON_SIZE, NULL);
710         if (INKSCAPE->menus != NULL)
711             retval = true;
712     }
713     g_free(fn);
714     return retval;
717 /**
718  * We use '.' as separator
719  * \param inkscape Unused
720  */
721 Inkscape::XML::Node *
722 inkscape_get_repr (Inkscape::Application *inkscape, const gchar *key)
724     if (key == NULL) {
725         return NULL;
726     }
728     Inkscape::XML::Node *repr = Inkscape::Preferences::get()->root();
729     if (!repr) return NULL;
730     g_assert (!(strcmp (repr->name(), "inkscape")));
732     gchar const *s = key;
733     while ((s) && (*s)) {
735         /* Find next name */
736         gchar const *e = strchr (s, '.');
737         guint len;
738         if (e) {
739             len = e++ - s;
740         } else {
741             len = strlen (s);
742         }
744         Inkscape::XML::Node* child;
745         for (child = repr->firstChild(); child != NULL; child = child->next()) {
746             gchar const *id = child->attribute("id");
747             if ((id) && (strlen (id) == len) && (!strncmp (id, s, len)))
748             {
749                 break;
750             }
751         }
752         if (child == NULL) {
753             return NULL;
754         }
756         repr = child;
757         s = e;
758     }
759     return repr;
764 void
765 inkscape_selection_modified (Inkscape::Selection *selection, guint flags)
767     if (Inkscape::NSApplication::Application::getNewGui()) {
768         Inkscape::NSApplication::Editor::selectionModified (selection, flags);
769         return;
770     }
771     g_return_if_fail (selection != NULL);
773     if (DESKTOP_IS_ACTIVE (selection->desktop())) {
774         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[MODIFY_SELECTION], 0, selection, flags);
775     }
779 void
780 inkscape_selection_changed (Inkscape::Selection * selection)
782     if (Inkscape::NSApplication::Application::getNewGui()) {
783         Inkscape::NSApplication::Editor::selectionChanged (selection);
784         return;
785     }
786     g_return_if_fail (selection != NULL);
788     if (DESKTOP_IS_ACTIVE (selection->desktop())) {
789         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, selection);
790     }
793 void
794 inkscape_subselection_changed (SPDesktop *desktop)
796     if (Inkscape::NSApplication::Application::getNewGui()) {
797         Inkscape::NSApplication::Editor::subSelectionChanged (desktop);
798         return;
799     }
800     g_return_if_fail (desktop != NULL);
802     if (DESKTOP_IS_ACTIVE (desktop)) {
803         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SUBSELECTION], 0, desktop);
804     }
808 void
809 inkscape_selection_set (Inkscape::Selection * selection)
811     if (Inkscape::NSApplication::Application::getNewGui()) {
812         Inkscape::NSApplication::Editor::selectionSet (selection);
813         return;
814     }
815     g_return_if_fail (selection != NULL);
817     if (DESKTOP_IS_ACTIVE (selection->desktop())) {
818         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, selection);
819         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, selection);
820     }
824 void
825 inkscape_eventcontext_set (SPEventContext * eventcontext)
827     if (Inkscape::NSApplication::Application::getNewGui()) {
828         Inkscape::NSApplication::Editor::eventContextSet (eventcontext);
829         return;
830     }
831     g_return_if_fail (eventcontext != NULL);
832     g_return_if_fail (SP_IS_EVENT_CONTEXT (eventcontext));
834     if (DESKTOP_IS_ACTIVE (eventcontext->desktop)) {
835         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, eventcontext);
836     }
840 void
841 inkscape_add_desktop (SPDesktop * desktop)
843     g_return_if_fail (desktop != NULL);
845     if (Inkscape::NSApplication::Application::getNewGui())
846     {
847         Inkscape::NSApplication::Editor::addDesktop (desktop);
848         return;
849     }
850     g_return_if_fail (inkscape != NULL);
852     g_assert (!g_slist_find (inkscape->desktops, desktop));
854     inkscape->desktops = g_slist_append (inkscape->desktops, desktop);
856     if (DESKTOP_IS_ACTIVE (desktop)) {
857         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, desktop);
858         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, sp_desktop_event_context (desktop));
859         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, sp_desktop_selection (desktop));
860         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, sp_desktop_selection (desktop));
861     }
866 void
867 inkscape_remove_desktop (SPDesktop * desktop)
869     g_return_if_fail (desktop != NULL);
870     if (Inkscape::NSApplication::Application::getNewGui())
871     {
872         Inkscape::NSApplication::Editor::removeDesktop (desktop);
873         return;
874     }
875     g_return_if_fail (inkscape != NULL);
877     g_assert (g_slist_find (inkscape->desktops, desktop));
879     if (DESKTOP_IS_ACTIVE (desktop)) {
880         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DEACTIVATE_DESKTOP], 0, desktop);
881         if (inkscape->desktops->next != NULL) {
882             SPDesktop * new_desktop = (SPDesktop *) inkscape->desktops->next->data;
883             inkscape->desktops = g_slist_remove (inkscape->desktops, new_desktop);
884             inkscape->desktops = g_slist_prepend (inkscape->desktops, new_desktop);
885             g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, new_desktop);
886             g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, sp_desktop_event_context (new_desktop));
887             g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, sp_desktop_selection (new_desktop));
888             g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, sp_desktop_selection (new_desktop));
889         } else {
890             g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, NULL);
891             if (sp_desktop_selection(desktop))
892                 sp_desktop_selection(desktop)->clear();
893         }
894     }
896     inkscape->desktops = g_slist_remove (inkscape->desktops, desktop);
898     // if this was the last desktop, shut down the program
899     if (inkscape->desktops == NULL) {
900         inkscape_exit (inkscape);
901     }
906 void
907 inkscape_activate_desktop (SPDesktop * desktop)
909     g_return_if_fail (desktop != NULL);
910     if (Inkscape::NSApplication::Application::getNewGui())
911     {
912         Inkscape::NSApplication::Editor::activateDesktop (desktop);
913         return;
914     }
915     g_return_if_fail (inkscape != NULL);
917     if (DESKTOP_IS_ACTIVE (desktop)) {
918         return;
919     }
921     g_assert (g_slist_find (inkscape->desktops, desktop));
923     SPDesktop *current = (SPDesktop *) inkscape->desktops->data;
925     g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DEACTIVATE_DESKTOP], 0, current);
927     inkscape->desktops = g_slist_remove (inkscape->desktops, desktop);
928     inkscape->desktops = g_slist_prepend (inkscape->desktops, desktop);
930     g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, desktop);
931     g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, sp_desktop_event_context (desktop));
932     g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, sp_desktop_selection (desktop));
933     g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, sp_desktop_selection (desktop));
937 /**
938  *  Resends ACTIVATE_DESKTOP for current desktop; needed when a new desktop has got its window that dialogs will transientize to
939  */
940 void
941 inkscape_reactivate_desktop (SPDesktop * desktop)
943     g_return_if_fail (desktop != NULL);
944     if (Inkscape::NSApplication::Application::getNewGui())
945     {
946         Inkscape::NSApplication::Editor::reactivateDesktop (desktop);
947         return;
948     }
949     g_return_if_fail (inkscape != NULL);
951     if (DESKTOP_IS_ACTIVE (desktop))
952         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, desktop);
957 SPDesktop *
958 inkscape_find_desktop_by_dkey (unsigned int dkey)
960     for (GSList *r = inkscape->desktops; r; r = r->next) {
961         if (((SPDesktop *) r->data)->dkey == dkey)
962             return ((SPDesktop *) r->data);
963     }
964     return NULL;
970 unsigned int
971 inkscape_maximum_dkey()
973     unsigned int dkey = 0;
975     for (GSList *r = inkscape->desktops; r; r = r->next) {
976         if (((SPDesktop *) r->data)->dkey > dkey)
977             dkey = ((SPDesktop *) r->data)->dkey;
978     }
980     return dkey;
985 SPDesktop *
986 inkscape_next_desktop ()
988     SPDesktop *d = NULL;
989     unsigned int dkey_current = ((SPDesktop *) inkscape->desktops->data)->dkey;
991     if (dkey_current < inkscape_maximum_dkey()) {
992         // find next existing
993         for (unsigned int i = dkey_current + 1; i <= inkscape_maximum_dkey(); i++) {
994             d = inkscape_find_desktop_by_dkey (i);
995             if (d) {
996                 break;
997             }
998         }
999     } else {
1000         // find first existing
1001         for (unsigned int i = 0; i <= inkscape_maximum_dkey(); i++) {
1002             d = inkscape_find_desktop_by_dkey (i);
1003             if (d) {
1004                 break;
1005             }
1006         }
1007     }
1009     g_assert (d);
1011     return d;
1016 SPDesktop *
1017 inkscape_prev_desktop ()
1019     SPDesktop *d = NULL;
1020     unsigned int dkey_current = ((SPDesktop *) inkscape->desktops->data)->dkey;
1022     if (dkey_current > 0) {
1023         // find prev existing
1024         for (signed int i = dkey_current - 1; i >= 0; i--) {
1025             d = inkscape_find_desktop_by_dkey (i);
1026             if (d) {
1027                 break;
1028             }
1029         }
1030     }
1031     if (!d) {
1032         // find last existing
1033         d = inkscape_find_desktop_by_dkey (inkscape_maximum_dkey());
1034     }
1036     g_assert (d);
1038     return d;
1043 void
1044 inkscape_switch_desktops_next ()
1046     inkscape_next_desktop()->presentWindow();
1051 void
1052 inkscape_switch_desktops_prev ()
1054     inkscape_prev_desktop()->presentWindow();
1059 void
1060 inkscape_dialogs_hide ()
1062     if (Inkscape::NSApplication::Application::getNewGui())
1063         Inkscape::NSApplication::Editor::hideDialogs();
1064     else
1065     {
1066         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DIALOGS_HIDE], 0);
1067         inkscape->dialogs_toggle = FALSE;
1068     }
1073 void
1074 inkscape_dialogs_unhide ()
1076     if (Inkscape::NSApplication::Application::getNewGui())
1077         Inkscape::NSApplication::Editor::unhideDialogs();
1078     else
1079     {
1080         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DIALOGS_UNHIDE], 0);
1081         inkscape->dialogs_toggle = TRUE;
1082     }
1087 void
1088 inkscape_dialogs_toggle ()
1090     if (inkscape->dialogs_toggle) {
1091         inkscape_dialogs_hide ();
1092     } else {
1093         inkscape_dialogs_unhide ();
1094     }
1097 void
1098 inkscape_external_change ()
1100     g_return_if_fail (inkscape != NULL);
1102     g_signal_emit (G_OBJECT (inkscape), inkscape_signals[EXTERNAL_CHANGE], 0);
1105 /**
1106  * fixme: These need probably signals too
1107  */
1108 void
1109 inkscape_add_document (SPDocument *document)
1111     g_return_if_fail (document != NULL);
1113     if (!Inkscape::NSApplication::Application::getNewGui())
1114     {
1115         g_assert (!g_slist_find (inkscape->documents, document));
1116         inkscape->documents = g_slist_append (inkscape->documents, document);
1117     }
1118     else
1119     {
1120         Inkscape::NSApplication::Editor::addDocument (document);
1121     }
1126 void
1127 inkscape_remove_document (SPDocument *document)
1129     g_return_if_fail (document != NULL);
1131     if (!Inkscape::NSApplication::Application::getNewGui())
1132     {
1133         g_assert (g_slist_find (inkscape->documents, document));
1134         inkscape->documents = g_slist_remove (inkscape->documents, document);
1135     }
1136     else
1137     {
1138         Inkscape::NSApplication::Editor::removeDocument (document);
1139     }
1141     return;
1144 SPDesktop *
1145 inkscape_active_desktop (void)
1147     if (Inkscape::NSApplication::Application::getNewGui())
1148         return Inkscape::NSApplication::Editor::getActiveDesktop();
1150     if (inkscape->desktops == NULL) {
1151         return NULL;
1152     }
1154     return (SPDesktop *) inkscape->desktops->data;
1157 SPDocument *
1158 inkscape_active_document (void)
1160     if (Inkscape::NSApplication::Application::getNewGui())
1161         return Inkscape::NSApplication::Editor::getActiveDocument();
1163     if (SP_ACTIVE_DESKTOP) {
1164         return sp_desktop_document (SP_ACTIVE_DESKTOP);
1165     }
1167     return NULL;
1170 bool inkscape_is_sole_desktop_for_document(SPDesktop const &desktop) {
1171     SPDocument const* document = desktop.doc();
1172     if (!document) {
1173         return false;
1174     }
1175     for ( GSList *iter = inkscape->desktops ; iter ; iter = iter->next ) {
1176         SPDesktop *other_desktop=(SPDesktop *)iter->data;
1177         SPDocument *other_document=other_desktop->doc();
1178         if ( other_document == document && other_desktop != &desktop ) {
1179             return false;
1180         }
1181     }
1182     return true;
1185 SPEventContext *
1186 inkscape_active_event_context (void)
1188     if (SP_ACTIVE_DESKTOP) {
1189         return sp_desktop_event_context (SP_ACTIVE_DESKTOP);
1190     }
1192     return NULL;
1197 /*#####################
1198 # HELPERS
1199 #####################*/
1201 static bool
1202 inkscape_init_config (Inkscape::XML::Document *doc, const gchar *config_name, const gchar *skeleton,
1203                       unsigned int skel_size,
1204                       const gchar *e_mkdir,
1205                       const gchar *e_notdir,
1206                       const gchar *e_ccf,
1207                       const gchar *e_cwf,
1208                       const gchar *warn)
1210     gchar *dn = profile_path(NULL);
1211     bool use_gui = (Inkscape::NSApplication::Application::getNewGui())? Inkscape::NSApplication::Application::getUseGui() : inkscape->use_gui;
1212     if (!Inkscape::IO::file_test(dn, G_FILE_TEST_EXISTS)) {
1213         if (Inkscape::IO::mkdir_utf8name(dn))
1214         {
1215             if (use_gui) {
1216                 // Cannot create directory
1217                 gchar *safeDn = Inkscape::IO::sanitizeString(dn);
1218                 GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_mkdir, safeDn, warn);
1219                 gtk_dialog_run (GTK_DIALOG (w));
1220                 gtk_widget_destroy (w);
1221                 g_free(safeDn);
1222                 g_free (dn);
1223                 return false;
1224             } else {
1225                 g_warning(e_mkdir, dn, warn);
1226                 g_free (dn);
1227                 return false;
1228             }
1229         }
1230     } else if (!Inkscape::IO::file_test(dn, G_FILE_TEST_IS_DIR)) {
1231         if (use_gui) {
1232             // Not a directory
1233             gchar *safeDn = Inkscape::IO::sanitizeString(dn);
1234             GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_notdir, safeDn, warn);
1235             gtk_dialog_run (GTK_DIALOG (w));
1236             gtk_widget_destroy (w);
1237             g_free( safeDn );
1238             g_free (dn);
1239             return false;
1240         } else {
1241             g_warning(e_notdir, dn, warn);
1242             g_free(dn);
1243             return false;
1244         }
1245     }
1246     g_free (dn);
1248     gchar *fn = profile_path(config_name);
1250     Inkscape::IO::dump_fopen_call(fn, "H");
1251     FILE *fh = Inkscape::IO::fopen_utf8name(fn, "w");
1252     if (!fh) {
1253         if (use_gui) {
1254             /* Cannot create file */
1255             gchar *safeFn = Inkscape::IO::sanitizeString(fn);
1256             GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_ccf, safeFn, warn);
1257             gtk_dialog_run (GTK_DIALOG (w));
1258             gtk_widget_destroy (w);
1259             g_free(safeFn);
1260             g_free (fn);
1261             return false;
1262         } else {
1263             g_warning(e_ccf, fn, warn);
1264             g_free(fn);
1265             return false;
1266         }
1267     }
1268     if ( fwrite(skeleton, 1, skel_size, fh) != skel_size ) {
1269         if (use_gui) {
1270             /* Cannot create file */
1271             gchar *safeFn = Inkscape::IO::sanitizeString(fn);
1272             GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_cwf, safeFn, warn);
1273             gtk_dialog_run (GTK_DIALOG (w));
1274             gtk_widget_destroy (w);
1275             g_free(safeFn);
1276             g_free (fn);
1277             fclose(fh);
1278             return false;
1279         } else {
1280             g_warning(e_cwf, fn, warn);
1281             g_free(fn);
1282             fclose(fh);
1283             return false;
1284         }
1285     }
1287     g_free(fn);
1288     fclose(fh);
1289     return true;
1292 void
1293 inkscape_refresh_display (Inkscape::Application *inkscape)
1295     for (GSList *l = inkscape->desktops; l != NULL; l = l->next) {
1296         (static_cast<Inkscape::UI::View::View*>(l->data))->requestRedraw();
1297     }
1301 /**
1302  *  Handler for Inkscape's Exit verb.  This emits the shutdown signal,
1303  *  saves the preferences if appropriate, and quits.
1304  */
1305 void
1306 inkscape_exit (Inkscape::Application *inkscape)
1308     g_assert (INKSCAPE);
1310     //emit shutdown signal so that dialogs could remember layout
1311     g_signal_emit (G_OBJECT (INKSCAPE), inkscape_signals[SHUTDOWN_SIGNAL], 0);
1313     Inkscape::Preferences::save();
1314     gtk_main_quit ();
1317 gchar *
1318 homedir_path(const char *filename)
1320     static const gchar *homedir = NULL;
1321     if (!homedir) {
1322         homedir = g_get_home_dir();
1323         gchar* utf8Path = g_filename_to_utf8( homedir, -1, NULL, NULL, NULL );
1324         if ( utf8Path )
1325         {
1326                 homedir = utf8Path;
1327                 if (!g_utf8_validate(homedir, -1, NULL)) {
1328                     g_warning( "g_get_home_dir() post A IS NOT UTF-8" );
1329                 }
1330         }
1331     }
1332     if (!homedir) {
1333         gchar * path = g_path_get_dirname(INKSCAPE->argv0);
1334         gchar* utf8Path = g_filename_to_utf8( path, -1, NULL, NULL, NULL );
1335         g_free(path);
1336         if ( utf8Path )
1337         {
1338             homedir = utf8Path;
1339             if (!g_utf8_validate(homedir, -1, NULL)) {
1340                 g_warning( "g_get_home_dir() post B IS NOT UTF-8" );
1341             }
1342         }
1343     }
1344     return g_build_filename(homedir, filename, NULL);
1348 /**
1349  * Get, or guess, or decide the location where the preferences.xml
1350  * file should be located.
1351  */
1352 gchar *
1353 profile_path(const char *filename)
1355     static const gchar *prefdir = NULL;
1356     if (!prefdir) {
1357 #ifdef HAS_SHGetSpecialFolderLocation
1358         // prefer c:\Documents and Settings\UserName\Application Data\ to
1359         // c:\Documents and Settings\userName\;
1360         if (!prefdir) {
1361             ITEMIDLIST *pidl = 0;
1362             if ( SHGetSpecialFolderLocation( NULL, CSIDL_APPDATA, &pidl ) == NOERROR ) {
1363                 gchar * utf8Path = NULL;
1365                 if ( PrintWin32::is_os_wide() ) {
1366                     wchar_t pathBuf[MAX_PATH+1];
1367                     g_assert(sizeof(wchar_t) == sizeof(gunichar2));
1369                     if ( SHGetPathFromIDListW( pidl, pathBuf ) ) {
1370                         utf8Path = g_utf16_to_utf8( (gunichar2*)(&pathBuf[0]), -1, NULL, NULL, NULL );
1371                     }
1372                 } else {
1373                     char pathBuf[MAX_PATH+1];
1375                     if ( SHGetPathFromIDListA( pidl, pathBuf ) ) {
1376                         utf8Path = g_filename_to_utf8( pathBuf, -1, NULL, NULL, NULL );
1377                     }
1378                 }
1380                 if ( utf8Path ) {
1381                     if (!g_utf8_validate(utf8Path, -1, NULL)) {
1382                         g_warning( "SHGetPathFromIDList%c() resulted in invalid UTF-8", (PrintWin32::is_os_wide() ? 'W' : 'A') );
1383                         g_free( utf8Path );
1384                         utf8Path = 0;
1385                     } else {
1386                         prefdir = utf8Path;
1387                     }
1388                 }
1391                 /* not compiling yet...
1393                 // Remember to free the list pointer
1394                 IMalloc * imalloc = 0;
1395                 if ( SHGetMalloc(&imalloc) == NOERROR) {
1396                     imalloc->lpVtbl->Free( imalloc, pidl );
1397                     imalloc->lpVtbl->Release( imalloc );
1398                 }
1399                 */
1400             }
1401         }
1402 #endif
1403         if (!prefdir) {
1404             prefdir = homedir_path(NULL);
1405         }
1406     }
1407     return g_build_filename(prefdir, INKSCAPE_PROFILE_DIR, filename, NULL);
1410 Inkscape::XML::Node *
1411 inkscape_get_menus (Inkscape::Application * inkscape)
1413     Inkscape::XML::Node *repr = inkscape->menus->root();
1414     g_assert (!(strcmp (repr->name(), "inkscape")));
1415     return repr->firstChild();
1418 void
1419 inkscape_get_all_desktops(std::list< SPDesktop* >& listbuf)
1421     for(GSList* l = inkscape->desktops; l != NULL; l = l->next) {
1422         listbuf.push_back(static_cast< SPDesktop* >(l->data));
1423     }
1428 /*
1429   Local Variables:
1430   mode:c++
1431   c-file-style:"stroustrup"
1432   c-file-offsets:((innamespace . 0)(inline-open . 0))
1433   indent-tabs-mode:nil
1434   fill-column:99
1435   End:
1436 */
1437 // vim: expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :