Code

9264e6010ffed299e44fc1c927136ef21c93c670
[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 <set>
22 #include "debug/simple-event.h"
23 #include "debug/event-tracker.h"
25 #ifndef WIN32
26 # define HAS_PROC_SELF_EXE  //to get path of executable
27 #else
29 // For now to get at is_os_wide().
30 # include "extension/internal/win32.h"
31 using Inkscape::Extension::Internal::PrintWin32;
33 #define _WIN32_IE 0x0400
34 //#define HAS_SHGetSpecialFolderPath
35 #define HAS_SHGetSpecialFolderLocation
36 #define HAS_GetModuleFileName
37 # include <shlobj.h>
38 #endif
40 #include <signal.h>
42 #include <gtk/gtkmain.h>
43 #include <gtk/gtkmessagedialog.h>
44 #include <glib.h>
45 #include <glib/gstdio.h>
47 #include <glibmm/i18n.h>
48 #include <string>
49 #include <cstring>
50 #include "helper/sp-marshal.h"
51 #include "dialogs/debugdialog.h"
52 #include "dialogs/input.h"
53 #include "application/application.h"
54 #include "application/editor.h"
57 #include "document.h"
58 #include "desktop.h"
59 #include "desktop-handles.h"
60 #include "selection.h"
61 #include "event-context.h"
62 #include "inkscape-private.h"
63 #include "xml/repr.h"
64 #include "preferences.h"
65 #include "io/sys.h"
66 #include "message-stack.h"
68 #include "extension/init.h"
69 #include "extension/db.h"
70 #include "extension/output.h"
71 #include "extension/system.h"
73 static Inkscape::Application *inkscape = NULL;
75 /* Backbones of configuration xml data */
76 #include "menus-skeleton.h"
78 enum {
79     MODIFY_SELECTION, // global: one of selections modified
80     CHANGE_SELECTION, // global: one of selections changed
81     CHANGE_SUBSELECTION, // global: one of subselections (text selection, gradient handle, etc) changed
82     SET_SELECTION, // global: one of selections set
83     SET_EVENTCONTEXT, // tool switched
84     ACTIVATE_DESKTOP, // some desktop got focus
85     DEACTIVATE_DESKTOP, // some desktop lost focus
86     SHUTDOWN_SIGNAL, // inkscape is quitting
87     DIALOGS_HIDE, // user pressed F12
88     DIALOGS_UNHIDE, // user pressed F12
89     EXTERNAL_CHANGE, // a document was changed by some external means (undo or XML editor); this
90                      // may not be reflected by a selection change and thus needs a separate signal
91     LAST_SIGNAL
92 };
94 #define DESKTOP_IS_ACTIVE(d) ((d) == inkscape->desktops->data)
97 /*################################
98 # FORWARD DECLARATIONS
99 ################################*/
101 gboolean inkscape_app_use_gui( Inkscape::Application const * app );
103 static void inkscape_class_init (Inkscape::ApplicationClass *klass);
104 static void inkscape_init (SPObject *object);
105 static void inkscape_dispose (GObject *object);
107 static void inkscape_activate_desktop_private (Inkscape::Application *inkscape, SPDesktop *desktop);
108 static void inkscape_deactivate_desktop_private (Inkscape::Application *inkscape, SPDesktop *desktop);
110 struct Inkscape::Application {
111     GObject object;
112     Inkscape::XML::Document *menus;
113     std::multiset<SPDocument *> document_set;
114     GSList *documents;
115     GSList *desktops;
116     gchar *argv0;
117     gboolean dialogs_toggle;
118     gboolean use_gui;         // may want to consider a virtual function
119                               // for overriding things like the warning dlg's
120     guint mapalt;
121 };
123 struct Inkscape::ApplicationClass {
124     GObjectClass object_class;
126     /* Signals */
127     void (* change_selection) (Inkscape::Application * inkscape, Inkscape::Selection * selection);
128     void (* change_subselection) (Inkscape::Application * inkscape, SPDesktop *desktop);
129     void (* modify_selection) (Inkscape::Application * inkscape, Inkscape::Selection * selection, guint flags);
130     void (* set_selection) (Inkscape::Application * inkscape, Inkscape::Selection * selection);
131     void (* set_eventcontext) (Inkscape::Application * inkscape, SPEventContext * eventcontext);
132     void (* activate_desktop) (Inkscape::Application * inkscape, SPDesktop * desktop);
133     void (* deactivate_desktop) (Inkscape::Application * inkscape, SPDesktop * desktop);
134     void (* destroy_document) (Inkscape::Application *inkscape, SPDocument *doc);
135     void (* color_set) (Inkscape::Application *inkscape, SPColor *color, double opacity);
136     void (* shut_down) (Inkscape::Application *inkscape);
137     void (* dialogs_hide) (Inkscape::Application *inkscape);
138     void (* dialogs_unhide) (Inkscape::Application *inkscape);
139     void (* external_change) (Inkscape::Application *inkscape);
140 };
142 static GObjectClass * parent_class;
143 static guint inkscape_signals[LAST_SIGNAL] = {0};
145 static void (* segv_handler) (int) = SIG_DFL;
146 static void (* abrt_handler) (int) = SIG_DFL;
147 static void (* fpe_handler)  (int) = SIG_DFL;
148 static void (* ill_handler)  (int) = SIG_DFL;
149 static void (* bus_handler)  (int) = SIG_DFL;
151 #ifdef WIN32
152 #define INKSCAPE_PROFILE_DIR "Inkscape"
153 #else
154 #define INKSCAPE_PROFILE_DIR ".inkscape"
155 #endif
157 #define MENUS_FILE "menus.xml"
160 /**
161  *  Retrieves the GType for the Inkscape Application object.
162  */
163 GType
164 inkscape_get_type (void)
166     static GType type = 0;
167     if (!type) {
168         GTypeInfo info = {
169             sizeof (Inkscape::ApplicationClass),
170             NULL, NULL,
171             (GClassInitFunc) inkscape_class_init,
172             NULL, NULL,
173             sizeof (Inkscape::Application),
174             4,
175             (GInstanceInitFunc) inkscape_init,
176             NULL
177         };
178         type = g_type_register_static (G_TYPE_OBJECT, "Inkscape_Application", &info, (GTypeFlags)0);
179     }
180     return type;
184 /**
185  *  Initializes the inkscape class, registering all of its signal handlers
186  *  and virtual functions
187  */
188 static void
189 inkscape_class_init (Inkscape::ApplicationClass * klass)
191     GObjectClass * object_class;
193     object_class = (GObjectClass *) klass;
195     parent_class = (GObjectClass *)g_type_class_peek_parent (klass);
197     inkscape_signals[MODIFY_SELECTION] = g_signal_new ("modify_selection",
198                                G_TYPE_FROM_CLASS (klass),
199                                G_SIGNAL_RUN_FIRST,
200                                G_STRUCT_OFFSET (Inkscape::ApplicationClass, modify_selection),
201                                NULL, NULL,
202                                sp_marshal_NONE__POINTER_UINT,
203                                G_TYPE_NONE, 2,
204                                G_TYPE_POINTER, G_TYPE_UINT);
205     inkscape_signals[CHANGE_SELECTION] = g_signal_new ("change_selection",
206                                G_TYPE_FROM_CLASS (klass),
207                                G_SIGNAL_RUN_FIRST,
208                                G_STRUCT_OFFSET (Inkscape::ApplicationClass, change_selection),
209                                NULL, NULL,
210                                sp_marshal_NONE__POINTER,
211                                G_TYPE_NONE, 1,
212                                G_TYPE_POINTER);
213     inkscape_signals[CHANGE_SUBSELECTION] = g_signal_new ("change_subselection",
214                                G_TYPE_FROM_CLASS (klass),
215                                G_SIGNAL_RUN_FIRST,
216                                G_STRUCT_OFFSET (Inkscape::ApplicationClass, change_subselection),
217                                NULL, NULL,
218                                sp_marshal_NONE__POINTER,
219                                G_TYPE_NONE, 1,
220                                G_TYPE_POINTER);
221     inkscape_signals[SET_SELECTION] =    g_signal_new ("set_selection",
222                                G_TYPE_FROM_CLASS (klass),
223                                G_SIGNAL_RUN_FIRST,
224                                G_STRUCT_OFFSET (Inkscape::ApplicationClass, set_selection),
225                                NULL, NULL,
226                                sp_marshal_NONE__POINTER,
227                                G_TYPE_NONE, 1,
228                                G_TYPE_POINTER);
229     inkscape_signals[SET_EVENTCONTEXT] = g_signal_new ("set_eventcontext",
230                                G_TYPE_FROM_CLASS (klass),
231                                G_SIGNAL_RUN_FIRST,
232                                G_STRUCT_OFFSET (Inkscape::ApplicationClass, set_eventcontext),
233                                NULL, NULL,
234                                sp_marshal_NONE__POINTER,
235                                G_TYPE_NONE, 1,
236                                G_TYPE_POINTER);
237     inkscape_signals[ACTIVATE_DESKTOP] = g_signal_new ("activate_desktop",
238                                G_TYPE_FROM_CLASS (klass),
239                                G_SIGNAL_RUN_FIRST,
240                                G_STRUCT_OFFSET (Inkscape::ApplicationClass, activate_desktop),
241                                NULL, NULL,
242                                sp_marshal_NONE__POINTER,
243                                G_TYPE_NONE, 1,
244                                G_TYPE_POINTER);
245     inkscape_signals[DEACTIVATE_DESKTOP] = g_signal_new ("deactivate_desktop",
246                                G_TYPE_FROM_CLASS (klass),
247                                G_SIGNAL_RUN_FIRST,
248                                G_STRUCT_OFFSET (Inkscape::ApplicationClass, deactivate_desktop),
249                                NULL, NULL,
250                                sp_marshal_NONE__POINTER,
251                                G_TYPE_NONE, 1,
252                                G_TYPE_POINTER);
253     inkscape_signals[SHUTDOWN_SIGNAL] =        g_signal_new ("shut_down",
254                                G_TYPE_FROM_CLASS (klass),
255                                G_SIGNAL_RUN_FIRST,
256                                G_STRUCT_OFFSET (Inkscape::ApplicationClass, shut_down),
257                                NULL, NULL,
258                                g_cclosure_marshal_VOID__VOID,
259                                G_TYPE_NONE, 0);
260     inkscape_signals[DIALOGS_HIDE] =        g_signal_new ("dialogs_hide",
261                                G_TYPE_FROM_CLASS (klass),
262                                G_SIGNAL_RUN_FIRST,
263                                G_STRUCT_OFFSET (Inkscape::ApplicationClass, dialogs_hide),
264                                NULL, NULL,
265                                g_cclosure_marshal_VOID__VOID,
266                                G_TYPE_NONE, 0);
267     inkscape_signals[DIALOGS_UNHIDE] =        g_signal_new ("dialogs_unhide",
268                                G_TYPE_FROM_CLASS (klass),
269                                G_SIGNAL_RUN_FIRST,
270                                G_STRUCT_OFFSET (Inkscape::ApplicationClass, dialogs_unhide),
271                                NULL, NULL,
272                                g_cclosure_marshal_VOID__VOID,
273                                G_TYPE_NONE, 0);
274     inkscape_signals[EXTERNAL_CHANGE] =   g_signal_new ("external_change",
275                                G_TYPE_FROM_CLASS (klass),
276                                G_SIGNAL_RUN_FIRST,
277                                G_STRUCT_OFFSET (Inkscape::ApplicationClass, external_change),
278                                NULL, NULL,
279                                g_cclosure_marshal_VOID__VOID,
280                                G_TYPE_NONE, 0);
282     object_class->dispose = inkscape_dispose;
284     klass->activate_desktop = inkscape_activate_desktop_private;
285     klass->deactivate_desktop = inkscape_deactivate_desktop_private;
288 #ifdef WIN32
289 typedef int uid_t;
290 #define getuid() 0
291 #endif
293 /**
294  * static gint inkscape_autosave(gpointer);
295  *
296  * Callback passed to g_timeout_add_seconds()
297  * Responsible for autosaving all open documents
298  */
299 static gint inkscape_autosave(gpointer)
301     if (!inkscape->documents) { // nothing to autosave
302         return TRUE;
303     }
304     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
306     // Use UID for separating autosave-documents between users if directory is multiuser
307     uid_t uid = getuid();
309     Glib::ustring autosave_dir;
310     {
311         Glib::ustring tmp = prefs->getString("options.autosave", "path");
312         if (!tmp.empty()) {
313             autosave_dir = tmp;
314         } else {
315             autosave_dir = Glib::get_tmp_dir();
316         }
317     }
319     GDir *autosave_dir_ptr = g_dir_open(autosave_dir.c_str(), 0, NULL);
320     if( !autosave_dir_ptr ){
321         g_warning("Cannot open autosave directory!");
322         return TRUE;
323     }
325     time_t sptime = time(NULL);
326     struct tm *sptm = localtime(&sptime);
327     gchar sptstr[256];
328     strftime(sptstr, 256, "%Y_%m_%d_%H_%M_%S", sptm);
330     gint autosave_max = prefs->getInt("options.autosave", "max", 10);
332     gint docnum = 0;
334     SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Autosaving documents..."));
335     for (GSList *docList = inkscape->documents; docList; docList = docList->next) {
336         ++docnum;
338         // TODO replace this with SP_DOCUMENT() when linking issues are addressed:
339         SPDocument *doc = static_cast<SPDocument *>(docList->data);
340         Inkscape::XML::Node *repr = sp_document_repr_root(doc);
341         // g_debug("Document %d: \"%s\" %s", docnum, doc ? doc->name : "(null)", doc ? (doc->isModifiedSinceSave() ? "(dirty)" : "(clean)") : "(null)");
343         if (doc->isModifiedSinceSave()) {
344             gchar *oldest_autosave = 0;
345             const gchar  *filename = 0;
346             struct stat sb;
347             time_t min_time = 0;
348             gint count = 0;
350             // Look for previous autosaves
351             gchar* baseName = g_strdup_printf( "inkscape-autosave-%d", uid );
352             g_dir_rewind(autosave_dir_ptr);
353             while( (filename = g_dir_read_name(autosave_dir_ptr)) != NULL ){
354                 if ( strncmp(filename, baseName, strlen(baseName)) == 0 ){
355                     gchar* full_path = g_build_filename( autosave_dir.c_str(), filename, NULL );
356                     if ( g_stat(full_path, &sb) != -1 ) {
357                         if ( difftime(sb.st_ctime, min_time) < 0 || min_time == 0 ){
358                             min_time = sb.st_ctime;
359                             if ( oldest_autosave ) {
360                                 g_free(oldest_autosave);
361                             }
362                             oldest_autosave = g_strdup(full_path);
363                         }
364                         count ++;
365                     }
366                     g_free(full_path);
367                 }
368             }
370             // g_debug("%d previous autosaves exists. Max = %d", count, autosave_max);
372             // Have we reached the limit for number of autosaves?
373             if ( count >= autosave_max ){
374                 // Remove the oldest file
375                 if ( oldest_autosave ) {
376                     unlink(oldest_autosave);
377                 }
378             }
380             if ( oldest_autosave ) {
381                 g_free(oldest_autosave);
382                 oldest_autosave = 0;
383             }
386             // Set the filename we will actually save to
387             g_free(baseName);
388             baseName = g_strdup_printf("inkscape-autosave-%d-%s-%03d.svg", uid, sptstr, docnum);
389             gchar* full_path = g_build_filename(autosave_dir.c_str(), baseName, NULL);
390             g_free(baseName);
391             baseName = 0;
393             // g_debug("Filename: %s", full_path);
395             // Try to save the file
396             FILE *file = Inkscape::IO::fopen_utf8name(full_path, "w");
397             gchar *errortext = 0;
398             if (file) {
399                 try{
400                     sp_repr_save_stream(repr->document(), file, SP_SVG_NS_URI);
401                 } catch (Inkscape::Extension::Output::no_extension_found &e) {
402                     errortext = g_strdup(_("Autosave failed! Could not find inkscape extension to save document."));
403                 } catch (Inkscape::Extension::Output::save_failed &e) {
404                     gchar *safeUri = Inkscape::IO::sanitizeString(full_path);
405                     errortext = g_strdup_printf(_("Autosave failed! File %s could not be saved."), safeUri);
406                     g_free(safeUri);
407                 }
408                 fclose(file);
409             }
410             else {
411                 gchar *safeUri = Inkscape::IO::sanitizeString(full_path);
412                 errortext = g_strdup_printf(_("Autosave failed! File %s could not be saved."), safeUri);
413                 g_free(safeUri);
414             }
416             if (errortext) {
417                 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, errortext);
418                 g_warning("%s", errortext);
419                 g_free(errortext);
420             }
422             g_free(full_path);
423         }
424     }
425     g_dir_close(autosave_dir_ptr);
427     SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Autosave complete."));
429     return TRUE;
432 void inkscape_autosave_init()
434     static guint32 autosave_timeout_id = 0;
435     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
437     // Turn off any previously initiated timeouts
438     if ( autosave_timeout_id ) {
439         g_source_remove(autosave_timeout_id);
440         autosave_timeout_id = 0;
441     }
443     // g_debug("options.autosave.enable = %d", prefs->getBool("options.autosave", "enable", true));
444     // Is autosave enabled?
445     if (!prefs->getBool("options.autosave", "enable", true)){
446         autosave_timeout_id = 0;
447     } else {
448         // Turn on autosave
449         guint32 timeout = prefs->getInt("options.autosave", "interval", 10) * 60;
450         // g_debug("options.autosave.interval = %d", prefs->getInt("options.autosave", "interval", 10));
451 #if GLIB_CHECK_VERSION(2,14,0)
452         autosave_timeout_id = g_timeout_add_seconds(timeout, inkscape_autosave, NULL);
453 #else
454         autosave_timeout_id = g_timeout_add(timeout * 1000, inkscape_autosave, NULL);
455 #endif
456     }
460 static void
461 inkscape_init (SPObject * object)
463     if (!inkscape) {
464         inkscape = (Inkscape::Application *) object;
465     } else {
466         g_assert_not_reached ();
467     }
469     new (&inkscape->document_set) std::multiset<SPDocument *>();
471     inkscape->menus = sp_repr_read_mem (_(menus_skeleton), MENUS_SKELETON_SIZE, NULL);
473     inkscape->documents = NULL;
474     inkscape->desktops = NULL;
476     inkscape->dialogs_toggle = TRUE;
478     inkscape->mapalt=GDK_MOD1_MASK;
481 static void
482 inkscape_dispose (GObject *object)
484     Inkscape::Application *inkscape = (Inkscape::Application *) object;
486     while (inkscape->documents) {
487         // we don't otherwise unref, so why here?
488         sp_document_unref((SPDocument *)inkscape->documents->data);
489     }
491     g_assert (!inkscape->desktops);
493     Inkscape::Preferences::unload();
495     if (inkscape->menus) {
496         /* fixme: This is not the best place */
497         Inkscape::GC::release(inkscape->menus);
498         inkscape->menus = NULL;
499     }
501     inkscape->document_set.~multiset();
503     G_OBJECT_CLASS (parent_class)->dispose (object);
505     gtk_main_quit ();
509 void
510 inkscape_ref (void)
512     if (inkscape)
513         g_object_ref (G_OBJECT (inkscape));
517 void
518 inkscape_unref (void)
520     if (inkscape)
521         g_object_unref (G_OBJECT (inkscape));
524 /* returns the mask of the keyboard modifier to map to Alt, zero if no mapping */
525 /* Needs to be a guint because gdktypes.h does not define a 'no-modifier' value */
526 guint
527 inkscape_mapalt() {
528     return inkscape->mapalt;
531 /* Sets the keyboard modifer to map to Alt. Zero switches off mapping, as does '1', which is the default */
532 void inkscape_mapalt(guint maskvalue)
534     if(maskvalue<2 || maskvalue> 5 ){  /* MOD5 is the highest defined in gdktypes.h */
535         inkscape->mapalt=0;
536     }else{
537         inkscape->mapalt=(GDK_MOD1_MASK << (maskvalue-1));
538     }
541 static void
542 inkscape_activate_desktop_private (Inkscape::Application */*inkscape*/, SPDesktop *desktop)
544     desktop->set_active (true);
548 static void
549 inkscape_deactivate_desktop_private (Inkscape::Application */*inkscape*/, SPDesktop *desktop)
551     desktop->set_active (false);
555 /* fixme: This is EVIL, and belongs to main after all */
557 #define SP_INDENT 8
560 static void
561 inkscape_crash_handler (int /*signum*/)
563     using Inkscape::Debug::SimpleEvent;
564     using Inkscape::Debug::EventTracker;
565     using Inkscape::Debug::Logger;
567     static gint recursion = FALSE;
569     /*
570      * reset all signal handlers: any further crashes should just be allowed
571      * to crash normally.
572      * */
573     signal (SIGSEGV, segv_handler );
574     signal (SIGABRT, abrt_handler );
575     signal (SIGFPE,  fpe_handler  );
576     signal (SIGILL,  ill_handler  );
577 #ifndef WIN32
578     signal (SIGBUS,  bus_handler  );
579 #endif
581     /* Stop bizarre loops */
582     if (recursion) {
583         abort ();
584     }
585     recursion = TRUE;
587     EventTracker<SimpleEvent<Inkscape::Debug::Event::CORE> > tracker("crash");
588     tracker.set<SimpleEvent<> >("emergency-save");
590     fprintf(stderr, "\nEmergency save activated!\n");
592     time_t sptime = time (NULL);
593     struct tm *sptm = localtime (&sptime);
594     gchar sptstr[256];
595     strftime (sptstr, 256, "%Y_%m_%d_%H_%M_%S", sptm);
597     gint count = 0;
598     GSList *savednames = NULL;
599     GSList *failednames = NULL;
600     for (GSList *l = inkscape->documents; l != NULL; l = l->next) {
601         SPDocument *doc;
602         Inkscape::XML::Node *repr;
603         doc = (SPDocument *) l->data;
604         repr = sp_document_repr_root (doc);
605         if (doc->isModifiedSinceSave()) {
606             const gchar *docname, *d0, *d;
607             gchar n[64], c[1024];
608             FILE *file;
610             /* originally, the document name was retrieved from
611              * the sodipod:docname attribute */
612             docname = doc->name;
613             if (docname) {
614                 /* fixme: Quick hack to remove emergency file suffix */
615                 d0 = strrchr ((char*)docname, '.');
616                 if (d0 && (d0 > docname)) {
617                     d0 = strrchr ((char*)(d0 - 1), '.');
618                     if (d0 && (d0 > docname)) {
619                         d = d0;
620                         while (isdigit (*d) || (*d == '.') || (*d == '_')) d += 1;
621                         if (*d) {
622                             memcpy (n, docname, MIN (d0 - docname - 1, 64));
623                             n[63] = '\0';
624                             docname = n;
625                         }
626                     }
627                 }
628             }
630             if (!docname || !*docname) docname = "emergency";
631             // try saving to the profile location
632             g_snprintf (c, 1024, "%.256s.%s.%d", docname, sptstr, count);
633             gchar * location = homedir_path(c);
634             Inkscape::IO::dump_fopen_call(location, "E");
635             file = Inkscape::IO::fopen_utf8name(location, "w");
636             g_free(location);
637             if (!file) {
638                 // try saving to /tmp
639                 g_snprintf (c, 1024, "/tmp/inkscape-%.256s.%s.%d", docname, sptstr, count);
640                 Inkscape::IO::dump_fopen_call(c, "G");
641                 file = Inkscape::IO::fopen_utf8name(c, "w");
642             }
643             if (!file) {
644                 // try saving to the current directory
645                 g_snprintf (c, 1024, "inkscape-%.256s.%s.%d", docname, sptstr, count);
646                 Inkscape::IO::dump_fopen_call(c, "F");
647                 file = Inkscape::IO::fopen_utf8name(c, "w");
648             }
649             if (file) {
650                 sp_repr_save_stream (repr->document(), file, SP_SVG_NS_URI);
651                 savednames = g_slist_prepend (savednames, g_strdup (c));
652                 fclose (file);
653             } else {
654                 failednames = g_slist_prepend (failednames, (doc->name) ? g_strdup (doc->name) : g_strdup (_("Untitled document")));
655             }
656             count++;
657         }
658     }
660     savednames = g_slist_reverse (savednames);
661     failednames = g_slist_reverse (failednames);
662     if (savednames) {
663         fprintf (stderr, "\nEmergency save document locations:\n");
664         for (GSList *l = savednames; l != NULL; l = l->next) {
665             fprintf (stderr, "  %s\n", (gchar *) l->data);
666         }
667     }
668     if (failednames) {
669         fprintf (stderr, "\nFailed to do emergency save for documents:\n");
670         for (GSList *l = failednames; l != NULL; l = l->next) {
671             fprintf (stderr, "  %s\n", (gchar *) l->data);
672         }
673     }
675     Inkscape::Preferences::unload();
677     fprintf (stderr, "Emergency save completed. Inkscape will close now.\n");
678     fprintf (stderr, "If you can reproduce this crash, please file a bug at www.inkscape.org\n");
679     fprintf (stderr, "with a detailed description of the steps leading to the crash, so we can fix it.\n");
681     /* Show nice dialog box */
683     char const *istr = _("Inkscape encountered an internal error and will close now.\n");
684     char const *sstr = _("Automatic backups of unsaved documents were done to the following locations:\n");
685     char const *fstr = _("Automatic backup of the following documents failed:\n");
686     gint nllen = strlen ("\n");
687     gint len = strlen (istr) + strlen (sstr) + strlen (fstr);
688     for (GSList *l = savednames; l != NULL; l = l->next) {
689         len = len + SP_INDENT + strlen ((gchar *) l->data) + nllen;
690     }
691     for (GSList *l = failednames; l != NULL; l = l->next) {
692         len = len + SP_INDENT + strlen ((gchar *) l->data) + nllen;
693     }
694     len += 1;
695     gchar *b = g_new (gchar, len);
696     gint pos = 0;
697     len = strlen (istr);
698     memcpy (b + pos, istr, len);
699     pos += len;
700     if (savednames) {
701         len = strlen (sstr);
702         memcpy (b + pos, sstr, len);
703         pos += len;
704         for (GSList *l = savednames; l != NULL; l = l->next) {
705             memset (b + pos, ' ', SP_INDENT);
706             pos += SP_INDENT;
707             len = strlen ((gchar *) l->data);
708             memcpy (b + pos, l->data, len);
709             pos += len;
710             memcpy (b + pos, "\n", nllen);
711             pos += nllen;
712         }
713     }
714     if (failednames) {
715         len = strlen (fstr);
716         memcpy (b + pos, fstr, len);
717         pos += len;
718         for (GSList *l = failednames; l != NULL; l = l->next) {
719             memset (b + pos, ' ', SP_INDENT);
720             pos += SP_INDENT;
721             len = strlen ((gchar *) l->data);
722             memcpy (b + pos, l->data, len);
723             pos += len;
724             memcpy (b + pos, "\n", nllen);
725             pos += nllen;
726         }
727     }
728     *(b + pos) = '\0';
730     if ( inkscape_get_instance() && inkscape_app_use_gui( inkscape_get_instance() ) ) {
731         GtkWidget *msgbox = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", b);
732         gtk_dialog_run (GTK_DIALOG (msgbox));
733         gtk_widget_destroy (msgbox);
734     }
735     else
736     {
737         g_message( "Error: %s", b );
738     }
739     g_free (b);
741     tracker.clear();
742     Logger::shutdown();
744     /* on exit, allow restored signal handler to take over and crash us */
749 void
750 inkscape_application_init (const gchar *argv0, gboolean use_gui)
752     inkscape = (Inkscape::Application *)g_object_new (SP_TYPE_INKSCAPE, NULL);
753     /* fixme: load application defaults */
755     segv_handler = signal (SIGSEGV, inkscape_crash_handler);
756     abrt_handler = signal (SIGABRT, inkscape_crash_handler);
757     fpe_handler  = signal (SIGFPE,  inkscape_crash_handler);
758     ill_handler  = signal (SIGILL,  inkscape_crash_handler);
759 #ifndef WIN32
760     bus_handler  = signal (SIGBUS,  inkscape_crash_handler);
761 #endif
763     inkscape->use_gui = use_gui;
764     inkscape->argv0 = g_strdup(argv0);
766     /* Load the preferences and menus; Later menu layout should be merged into prefs */
767     Inkscape::Preferences::use_gui = use_gui;
768     Inkscape::Preferences::load();
769     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
770     inkscape_load_menus(inkscape);
771     sp_input_load_from_preferences();
773     /* DebugDialog redirection.  On Linux, default to OFF, on Win32, default to ON.
774          * Use only if use_gui is enabled
775          */
776 #ifdef WIN32
777 #define DEFAULT_LOG_REDIRECT true
778 #else
779 #define DEFAULT_LOG_REDIRECT false
780 #endif
782     if (use_gui == TRUE && prefs->getBool("dialogs.debug", "redirect", DEFAULT_LOG_REDIRECT))
783     {
784                 Inkscape::UI::Dialogs::DebugDialog::getInstance()->captureLogMessages();
785     }
787     /* Check for global remapping of Alt key */
788     if(use_gui)
789     {
790         inkscape_mapalt(guint(prefs->getInt("options.mapalt", "value", 0)));
791     }
793     /* Initialize the extensions */
794     Inkscape::Extension::init();
796     inkscape_autosave_init();
798     return;
801 /**
802  *  Returns the current Inkscape::Application global object
803  */
804 Inkscape::Application *
805 inkscape_get_instance()
807         return inkscape;
810 gboolean inkscape_app_use_gui( Inkscape::Application const * app )
812     return app->use_gui;
815 /**
816  *  Menus management
817  *
818  */
819 bool inkscape_load_menus (Inkscape::Application */*inkscape*/)
821     gchar *fn = profile_path(MENUS_FILE);
822     gchar *menus_xml = NULL; gsize len = 0;
824     if (g_file_get_contents(fn, &menus_xml, &len, NULL)) {
825         // load the menus_xml file
826         INKSCAPE->menus = sp_repr_read_mem(menus_xml, len, NULL);
827         g_free(menus_xml);
828         if (INKSCAPE->menus) return true;
829     }
830     INKSCAPE->menus = sp_repr_read_mem(menus_skeleton, MENUS_SKELETON_SIZE, NULL);
831     if (INKSCAPE->menus) return true;
832     return false;
835 /**
836  * @deprecated Use the Preferences class instead, and try not to use _getNode
837  */
838 Inkscape::XML::Node *inkscape_get_repr(Inkscape::Application */*inkscape*/, const gchar *key)
840     Inkscape::Preferences *ps = Inkscape::Preferences::get();
841     return ps->_getNode(key);
845 void
846 inkscape_selection_modified (Inkscape::Selection *selection, guint flags)
848     if (Inkscape::NSApplication::Application::getNewGui()) {
849         Inkscape::NSApplication::Editor::selectionModified (selection, flags);
850         return;
851     }
852     g_return_if_fail (selection != NULL);
854     if (DESKTOP_IS_ACTIVE (selection->desktop())) {
855         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[MODIFY_SELECTION], 0, selection, flags);
856     }
860 void
861 inkscape_selection_changed (Inkscape::Selection * selection)
863     if (Inkscape::NSApplication::Application::getNewGui()) {
864         Inkscape::NSApplication::Editor::selectionChanged (selection);
865         return;
866     }
867     g_return_if_fail (selection != NULL);
869     if (DESKTOP_IS_ACTIVE (selection->desktop())) {
870         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, selection);
871     }
874 void
875 inkscape_subselection_changed (SPDesktop *desktop)
877     if (Inkscape::NSApplication::Application::getNewGui()) {
878         Inkscape::NSApplication::Editor::subSelectionChanged (desktop);
879         return;
880     }
881     g_return_if_fail (desktop != NULL);
883     if (DESKTOP_IS_ACTIVE (desktop)) {
884         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SUBSELECTION], 0, desktop);
885     }
889 void
890 inkscape_selection_set (Inkscape::Selection * selection)
892     if (Inkscape::NSApplication::Application::getNewGui()) {
893         Inkscape::NSApplication::Editor::selectionSet (selection);
894         return;
895     }
896     g_return_if_fail (selection != NULL);
898     if (DESKTOP_IS_ACTIVE (selection->desktop())) {
899         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, selection);
900         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, selection);
901     }
905 void
906 inkscape_eventcontext_set (SPEventContext * eventcontext)
908     if (Inkscape::NSApplication::Application::getNewGui()) {
909         Inkscape::NSApplication::Editor::eventContextSet (eventcontext);
910         return;
911     }
912     g_return_if_fail (eventcontext != NULL);
913     g_return_if_fail (SP_IS_EVENT_CONTEXT (eventcontext));
915     if (DESKTOP_IS_ACTIVE (eventcontext->desktop)) {
916         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, eventcontext);
917     }
921 void
922 inkscape_add_desktop (SPDesktop * desktop)
924     g_return_if_fail (desktop != NULL);
926     if (Inkscape::NSApplication::Application::getNewGui())
927     {
928         Inkscape::NSApplication::Editor::addDesktop (desktop);
929         return;
930     }
931     g_return_if_fail (inkscape != NULL);
933     g_assert (!g_slist_find (inkscape->desktops, desktop));
935     inkscape->desktops = g_slist_prepend (inkscape->desktops, desktop);
937     g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, desktop);
938     g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, sp_desktop_event_context (desktop));
939     g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, sp_desktop_selection (desktop));
940     g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, sp_desktop_selection (desktop));
945 void
946 inkscape_remove_desktop (SPDesktop * desktop)
948     g_return_if_fail (desktop != NULL);
949     if (Inkscape::NSApplication::Application::getNewGui())
950     {
951         Inkscape::NSApplication::Editor::removeDesktop (desktop);
952         return;
953     }
954     g_return_if_fail (inkscape != NULL);
956     g_assert (g_slist_find (inkscape->desktops, desktop));
958     if (DESKTOP_IS_ACTIVE (desktop)) {
959         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DEACTIVATE_DESKTOP], 0, desktop);
960         if (inkscape->desktops->next != NULL) {
961             SPDesktop * new_desktop = (SPDesktop *) inkscape->desktops->next->data;
962             inkscape->desktops = g_slist_remove (inkscape->desktops, new_desktop);
963             inkscape->desktops = g_slist_prepend (inkscape->desktops, new_desktop);
964             g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, new_desktop);
965             g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, sp_desktop_event_context (new_desktop));
966             g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, sp_desktop_selection (new_desktop));
967             g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, sp_desktop_selection (new_desktop));
968         } else {
969             g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, NULL);
970             if (sp_desktop_selection(desktop))
971                 sp_desktop_selection(desktop)->clear();
972         }
973     }
975     inkscape->desktops = g_slist_remove (inkscape->desktops, desktop);
977     // if this was the last desktop, shut down the program
978     if (inkscape->desktops == NULL) {
979         inkscape_exit (inkscape);
980     }
985 void
986 inkscape_activate_desktop (SPDesktop * desktop)
988     g_return_if_fail (desktop != NULL);
989     if (Inkscape::NSApplication::Application::getNewGui())
990     {
991         Inkscape::NSApplication::Editor::activateDesktop (desktop);
992         return;
993     }
994     g_return_if_fail (inkscape != NULL);
996     if (DESKTOP_IS_ACTIVE (desktop)) {
997         return;
998     }
1000     g_assert (g_slist_find (inkscape->desktops, desktop));
1002     SPDesktop *current = (SPDesktop *) inkscape->desktops->data;
1004     g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DEACTIVATE_DESKTOP], 0, current);
1006     inkscape->desktops = g_slist_remove (inkscape->desktops, desktop);
1007     inkscape->desktops = g_slist_prepend (inkscape->desktops, desktop);
1009     g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, desktop);
1010     g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, sp_desktop_event_context (desktop));
1011     g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, sp_desktop_selection (desktop));
1012     g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, sp_desktop_selection (desktop));
1016 /**
1017  *  Resends ACTIVATE_DESKTOP for current desktop; needed when a new desktop has got its window that dialogs will transientize to
1018  */
1019 void
1020 inkscape_reactivate_desktop (SPDesktop * desktop)
1022     g_return_if_fail (desktop != NULL);
1023     if (Inkscape::NSApplication::Application::getNewGui())
1024     {
1025         Inkscape::NSApplication::Editor::reactivateDesktop (desktop);
1026         return;
1027     }
1028     g_return_if_fail (inkscape != NULL);
1030     if (DESKTOP_IS_ACTIVE (desktop))
1031         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, desktop);
1036 SPDesktop *
1037 inkscape_find_desktop_by_dkey (unsigned int dkey)
1039     for (GSList *r = inkscape->desktops; r; r = r->next) {
1040         if (((SPDesktop *) r->data)->dkey == dkey)
1041             return ((SPDesktop *) r->data);
1042     }
1043     return NULL;
1049 unsigned int
1050 inkscape_maximum_dkey()
1052     unsigned int dkey = 0;
1054     for (GSList *r = inkscape->desktops; r; r = r->next) {
1055         if (((SPDesktop *) r->data)->dkey > dkey)
1056             dkey = ((SPDesktop *) r->data)->dkey;
1057     }
1059     return dkey;
1064 SPDesktop *
1065 inkscape_next_desktop ()
1067     SPDesktop *d = NULL;
1068     unsigned int dkey_current = ((SPDesktop *) inkscape->desktops->data)->dkey;
1070     if (dkey_current < inkscape_maximum_dkey()) {
1071         // find next existing
1072         for (unsigned int i = dkey_current + 1; i <= inkscape_maximum_dkey(); i++) {
1073             d = inkscape_find_desktop_by_dkey (i);
1074             if (d) {
1075                 break;
1076             }
1077         }
1078     } else {
1079         // find first existing
1080         for (unsigned int i = 0; i <= inkscape_maximum_dkey(); i++) {
1081             d = inkscape_find_desktop_by_dkey (i);
1082             if (d) {
1083                 break;
1084             }
1085         }
1086     }
1088     g_assert (d);
1090     return d;
1095 SPDesktop *
1096 inkscape_prev_desktop ()
1098     SPDesktop *d = NULL;
1099     unsigned int dkey_current = ((SPDesktop *) inkscape->desktops->data)->dkey;
1101     if (dkey_current > 0) {
1102         // find prev existing
1103         for (signed int i = dkey_current - 1; i >= 0; i--) {
1104             d = inkscape_find_desktop_by_dkey (i);
1105             if (d) {
1106                 break;
1107             }
1108         }
1109     }
1110     if (!d) {
1111         // find last existing
1112         d = inkscape_find_desktop_by_dkey (inkscape_maximum_dkey());
1113     }
1115     g_assert (d);
1117     return d;
1122 void
1123 inkscape_switch_desktops_next ()
1125     inkscape_next_desktop()->presentWindow();
1130 void
1131 inkscape_switch_desktops_prev ()
1133     inkscape_prev_desktop()->presentWindow();
1138 void
1139 inkscape_dialogs_hide ()
1141     if (Inkscape::NSApplication::Application::getNewGui())
1142         Inkscape::NSApplication::Editor::hideDialogs();
1143     else
1144     {
1145         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DIALOGS_HIDE], 0);
1146         inkscape->dialogs_toggle = FALSE;
1147     }
1152 void
1153 inkscape_dialogs_unhide ()
1155     if (Inkscape::NSApplication::Application::getNewGui())
1156         Inkscape::NSApplication::Editor::unhideDialogs();
1157     else
1158     {
1159         g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DIALOGS_UNHIDE], 0);
1160         inkscape->dialogs_toggle = TRUE;
1161     }
1166 void
1167 inkscape_dialogs_toggle ()
1169     if (inkscape->dialogs_toggle) {
1170         inkscape_dialogs_hide ();
1171     } else {
1172         inkscape_dialogs_unhide ();
1173     }
1176 void
1177 inkscape_external_change ()
1179     g_return_if_fail (inkscape != NULL);
1181     g_signal_emit (G_OBJECT (inkscape), inkscape_signals[EXTERNAL_CHANGE], 0);
1184 /**
1185  * fixme: These need probably signals too
1186  */
1187 void
1188 inkscape_add_document (SPDocument *document)
1190     g_return_if_fail (document != NULL);
1192     if (!Inkscape::NSApplication::Application::getNewGui())
1193     {
1194         if ( inkscape->document_set.find(document) == inkscape->document_set.end() ) {
1196             inkscape->documents = g_slist_append (inkscape->documents, document);
1197         }
1198         inkscape->document_set.insert(document);
1199     }
1200     else
1201     {
1202         Inkscape::NSApplication::Editor::addDocument (document);
1203     }
1208 void
1209 inkscape_remove_document (SPDocument *document)
1211     g_return_if_fail (document != NULL);
1213     if (!Inkscape::NSApplication::Application::getNewGui())
1214     {
1215         inkscape->document_set.erase(document);
1216         if ( inkscape->document_set.find(document) != inkscape->document_set.end() ) {
1217             inkscape->documents = g_slist_remove (inkscape->documents, document);
1218         }
1219     }
1220     else
1221     {
1222         Inkscape::NSApplication::Editor::removeDocument (document);
1223     }
1225     return;
1228 SPDesktop *
1229 inkscape_active_desktop (void)
1231     if (Inkscape::NSApplication::Application::getNewGui())
1232         return Inkscape::NSApplication::Editor::getActiveDesktop();
1234     if (inkscape->desktops == NULL) {
1235         return NULL;
1236     }
1238     return (SPDesktop *) inkscape->desktops->data;
1241 SPDocument *
1242 inkscape_active_document (void)
1244     if (Inkscape::NSApplication::Application::getNewGui())
1245         return Inkscape::NSApplication::Editor::getActiveDocument();
1247     if (SP_ACTIVE_DESKTOP) {
1248         return sp_desktop_document (SP_ACTIVE_DESKTOP);
1249     }
1251     return NULL;
1254 bool inkscape_is_sole_desktop_for_document(SPDesktop const &desktop) {
1255     SPDocument const* document = desktop.doc();
1256     if (!document) {
1257         return false;
1258     }
1259     for ( GSList *iter = inkscape->desktops ; iter ; iter = iter->next ) {
1260         SPDesktop *other_desktop=(SPDesktop *)iter->data;
1261         SPDocument *other_document=other_desktop->doc();
1262         if ( other_document == document && other_desktop != &desktop ) {
1263             return false;
1264         }
1265     }
1266     return true;
1269 SPEventContext *
1270 inkscape_active_event_context (void)
1272     if (SP_ACTIVE_DESKTOP) {
1273         return sp_desktop_event_context (SP_ACTIVE_DESKTOP);
1274     }
1276     return NULL;
1281 /*#####################
1282 # HELPERS
1283 #####################*/
1285 void
1286 inkscape_refresh_display (Inkscape::Application *inkscape)
1288     for (GSList *l = inkscape->desktops; l != NULL; l = l->next) {
1289         (static_cast<Inkscape::UI::View::View*>(l->data))->requestRedraw();
1290     }
1294 /**
1295  *  Handler for Inkscape's Exit verb.  This emits the shutdown signal,
1296  *  saves the preferences if appropriate, and quits.
1297  */
1298 void
1299 inkscape_exit (Inkscape::Application */*inkscape*/)
1301     g_assert (INKSCAPE);
1303     //emit shutdown signal so that dialogs could remember layout
1304     g_signal_emit (G_OBJECT (INKSCAPE), inkscape_signals[SHUTDOWN_SIGNAL], 0);
1306     Inkscape::Preferences::unload();
1307     gtk_main_quit ();
1310 char *
1311 homedir_path(const char *filename)
1313     static const gchar *homedir = NULL;
1314     if (!homedir) {
1315         homedir = g_get_home_dir();
1316     }
1317     if (!homedir) {
1318 // TODO check this. It looks broken
1319         gchar * path = g_path_get_dirname(INKSCAPE->argv0);
1320     }
1321     return g_build_filename(homedir, filename, NULL);
1325 /**
1326  * Get, or guess, or decide the location where the preferences.xml
1327  * file should be located.
1328  */
1329 gchar *
1330 profile_path(const char *filename)
1332     static const gchar *prefdir = NULL;
1333     if (!prefdir) {
1334 #ifdef HAS_SHGetSpecialFolderLocation
1335         // prefer c:\Documents and Settings\UserName\Application Data\ to
1336         // c:\Documents and Settings\userName\;
1337         if (!prefdir) {
1338             ITEMIDLIST *pidl = 0;
1339             if ( SHGetSpecialFolderLocation( NULL, CSIDL_APPDATA, &pidl ) == NOERROR ) {
1340                 gchar * utf8Path = NULL;
1342                 if ( PrintWin32::is_os_wide() ) {
1343                     wchar_t pathBuf[MAX_PATH+1];
1344                     g_assert(sizeof(wchar_t) == sizeof(gunichar2));
1346                     if ( SHGetPathFromIDListW( pidl, pathBuf ) ) {
1347                         utf8Path = g_utf16_to_utf8( (gunichar2*)(&pathBuf[0]), -1, NULL, NULL, NULL );
1348                     }
1349                 } else {
1350                     char pathBuf[MAX_PATH+1];
1352                     if ( SHGetPathFromIDListA( pidl, pathBuf ) ) {
1353                         utf8Path = g_filename_to_utf8( pathBuf, -1, NULL, NULL, NULL );
1354                     }
1355                 }
1357                 if ( utf8Path ) {
1358                     if (!g_utf8_validate(utf8Path, -1, NULL)) {
1359                         g_warning( "SHGetPathFromIDList%c() resulted in invalid UTF-8", (PrintWin32::is_os_wide() ? 'W' : 'A') );
1360                         g_free( utf8Path );
1361                         utf8Path = 0;
1362                     } else {
1363                         prefdir = utf8Path;
1364                     }
1365                 }
1368                 /* not compiling yet...
1370                 // Remember to free the list pointer
1371                 IMalloc * imalloc = 0;
1372                 if ( SHGetMalloc(&imalloc) == NOERROR) {
1373                     imalloc->lpVtbl->Free( imalloc, pidl );
1374                     imalloc->lpVtbl->Release( imalloc );
1375                 }
1376                 */
1377             }
1378         }
1379 #endif
1380         if (!prefdir) {
1381             prefdir = homedir_path(NULL);
1382         }
1383     }
1384     return g_build_filename(prefdir, INKSCAPE_PROFILE_DIR, filename, NULL);
1387 Inkscape::XML::Node *
1388 inkscape_get_menus (Inkscape::Application * inkscape)
1390     Inkscape::XML::Node *repr = inkscape->menus->root();
1391     g_assert (!(strcmp (repr->name(), "inkscape")));
1392     return repr->firstChild();
1395 void
1396 inkscape_get_all_desktops(std::list< SPDesktop* >& listbuf)
1398     for(GSList* l = inkscape->desktops; l != NULL; l = l->next) {
1399         listbuf.push_back(static_cast< SPDesktop* >(l->data));
1400     }
1405 /*
1406   Local Variables:
1407   mode:c++
1408   c-file-style:"stroustrup"
1409   c-file-offsets:((innamespace . 0)(inline-open . 0))
1410   indent-tabs-mode:nil
1411   fill-column:99
1412   End:
1413 */
1414 // vim: expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :