1 /** @file
2 * @brief Legacy interface to main application
3 */
4 /* Authors:
5 * Lauris Kaplinski <lauris@kaplinski.com>
6 * bulia byak <buliabyak@users.sf.net>
7 *
8 * Copyright (C) 1999-2005 authors
9 * g++ port Copyright (C) 2003 Nathan Hurst
10 *
11 * Released under GNU GPL, read the file 'COPYING' for more information
12 */
14 #ifdef HAVE_CONFIG_H
15 # include "config.h"
16 #endif
19 #include <map>
20 #include "debug/simple-event.h"
21 #include "debug/event-tracker.h"
23 #ifndef WIN32
24 # define HAS_PROC_SELF_EXE //to get path of executable
25 #else
27 // For now to get at is_os_wide().
28 # include "extension/internal/win32.h"
29 using Inkscape::Extension::Internal::PrintWin32;
31 #define _WIN32_IE 0x0400
32 //#define HAS_SHGetSpecialFolderPath
33 #define HAS_SHGetSpecialFolderLocation
34 #define HAS_GetModuleFileName
35 # include <shlobj.h>
36 #endif
38 #include <cstring>
39 #include <glib/gstdio.h>
40 #include <glib.h>
41 #include <glibmm/i18n.h>
42 #include <gtk/gtkmain.h>
43 #include <gtk/gtkmessagedialog.h>
44 #include <signal.h>
45 #include <string>
46 #include "application/application.h"
47 #include "application/editor.h"
48 #include "desktop.h"
49 #include "desktop-handles.h"
50 #include "dialogs/input.h"
51 #include "document.h"
52 #include "event-context.h"
53 #include "extension/db.h"
54 #include "extension/init.h"
55 #include "extension/output.h"
56 #include "extension/system.h"
57 #include "helper/sp-marshal.h"
58 #include "inkscape-private.h"
59 #include "io/sys.h"
60 #include "message-stack.h"
61 #include "preferences.h"
62 #include "selection.h"
63 #include "ui/dialog/debug.h"
64 #include "xml/repr.h"
66 static Inkscape::Application *inkscape = NULL;
68 /* Backbones of configuration xml data */
69 #include "menus-skeleton.h"
71 enum {
72 MODIFY_SELECTION, // global: one of selections modified
73 CHANGE_SELECTION, // global: one of selections changed
74 CHANGE_SUBSELECTION, // global: one of subselections (text selection, gradient handle, etc) changed
75 SET_SELECTION, // global: one of selections set
76 SET_EVENTCONTEXT, // tool switched
77 ACTIVATE_DESKTOP, // some desktop got focus
78 DEACTIVATE_DESKTOP, // some desktop lost focus
79 SHUTDOWN_SIGNAL, // inkscape is quitting
80 DIALOGS_HIDE, // user pressed F12
81 DIALOGS_UNHIDE, // user pressed F12
82 EXTERNAL_CHANGE, // a document was changed by some external means (undo or XML editor); this
83 // may not be reflected by a selection change and thus needs a separate signal
84 LAST_SIGNAL
85 };
87 #define DESKTOP_IS_ACTIVE(d) ((d) == inkscape->desktops->data)
90 /*################################
91 # FORWARD DECLARATIONS
92 ################################*/
94 gboolean inkscape_app_use_gui( Inkscape::Application const * app );
96 static void inkscape_class_init (Inkscape::ApplicationClass *klass);
97 static void inkscape_init (SPObject *object);
98 static void inkscape_dispose (GObject *object);
100 static void inkscape_activate_desktop_private (Inkscape::Application *inkscape, SPDesktop *desktop);
101 static void inkscape_deactivate_desktop_private (Inkscape::Application *inkscape, SPDesktop *desktop);
103 struct Inkscape::Application {
104 GObject object;
105 Inkscape::XML::Document *menus;
106 std::map<SPDocument *, int> document_set;
107 GSList *desktops;
108 gchar *argv0;
109 gboolean dialogs_toggle;
110 gboolean use_gui; // may want to consider a virtual function
111 // for overriding things like the warning dlg's
112 guint mapalt;
113 guint trackalt;
114 };
116 struct Inkscape::ApplicationClass {
117 GObjectClass object_class;
119 /* Signals */
120 void (* change_selection) (Inkscape::Application * inkscape, Inkscape::Selection * selection);
121 void (* change_subselection) (Inkscape::Application * inkscape, SPDesktop *desktop);
122 void (* modify_selection) (Inkscape::Application * inkscape, Inkscape::Selection * selection, guint flags);
123 void (* set_selection) (Inkscape::Application * inkscape, Inkscape::Selection * selection);
124 void (* set_eventcontext) (Inkscape::Application * inkscape, SPEventContext * eventcontext);
125 void (* activate_desktop) (Inkscape::Application * inkscape, SPDesktop * desktop);
126 void (* deactivate_desktop) (Inkscape::Application * inkscape, SPDesktop * desktop);
127 void (* destroy_document) (Inkscape::Application *inkscape, SPDocument *doc);
128 void (* color_set) (Inkscape::Application *inkscape, SPColor *color, double opacity);
129 void (* shut_down) (Inkscape::Application *inkscape);
130 void (* dialogs_hide) (Inkscape::Application *inkscape);
131 void (* dialogs_unhide) (Inkscape::Application *inkscape);
132 void (* external_change) (Inkscape::Application *inkscape);
133 };
135 static GObjectClass * parent_class;
136 static guint inkscape_signals[LAST_SIGNAL] = {0};
138 static void (* segv_handler) (int) = SIG_DFL;
139 static void (* abrt_handler) (int) = SIG_DFL;
140 static void (* fpe_handler) (int) = SIG_DFL;
141 static void (* ill_handler) (int) = SIG_DFL;
142 static void (* bus_handler) (int) = SIG_DFL;
144 #define INKSCAPE_PROFILE_DIR "Inkscape"
145 #define INKSCAPE_LEGACY_PROFILE_DIR ".inkscape"
146 #define MENUS_FILE "menus.xml"
149 /**
150 * Retrieves the GType for the Inkscape Application object.
151 */
152 GType
153 inkscape_get_type (void)
154 {
155 static GType type = 0;
156 if (!type) {
157 GTypeInfo info = {
158 sizeof (Inkscape::ApplicationClass),
159 NULL, NULL,
160 (GClassInitFunc) inkscape_class_init,
161 NULL, NULL,
162 sizeof (Inkscape::Application),
163 4,
164 (GInstanceInitFunc) inkscape_init,
165 NULL
166 };
167 type = g_type_register_static (G_TYPE_OBJECT, "Inkscape_Application", &info, (GTypeFlags)0);
168 }
169 return type;
170 }
173 /**
174 * Initializes the inkscape class, registering all of its signal handlers
175 * and virtual functions
176 */
177 static void
178 inkscape_class_init (Inkscape::ApplicationClass * klass)
179 {
180 GObjectClass * object_class;
182 object_class = (GObjectClass *) klass;
184 parent_class = (GObjectClass *)g_type_class_peek_parent (klass);
186 inkscape_signals[MODIFY_SELECTION] = g_signal_new ("modify_selection",
187 G_TYPE_FROM_CLASS (klass),
188 G_SIGNAL_RUN_FIRST,
189 G_STRUCT_OFFSET (Inkscape::ApplicationClass, modify_selection),
190 NULL, NULL,
191 sp_marshal_NONE__POINTER_UINT,
192 G_TYPE_NONE, 2,
193 G_TYPE_POINTER, G_TYPE_UINT);
194 inkscape_signals[CHANGE_SELECTION] = g_signal_new ("change_selection",
195 G_TYPE_FROM_CLASS (klass),
196 G_SIGNAL_RUN_FIRST,
197 G_STRUCT_OFFSET (Inkscape::ApplicationClass, change_selection),
198 NULL, NULL,
199 sp_marshal_NONE__POINTER,
200 G_TYPE_NONE, 1,
201 G_TYPE_POINTER);
202 inkscape_signals[CHANGE_SUBSELECTION] = g_signal_new ("change_subselection",
203 G_TYPE_FROM_CLASS (klass),
204 G_SIGNAL_RUN_FIRST,
205 G_STRUCT_OFFSET (Inkscape::ApplicationClass, change_subselection),
206 NULL, NULL,
207 sp_marshal_NONE__POINTER,
208 G_TYPE_NONE, 1,
209 G_TYPE_POINTER);
210 inkscape_signals[SET_SELECTION] = g_signal_new ("set_selection",
211 G_TYPE_FROM_CLASS (klass),
212 G_SIGNAL_RUN_FIRST,
213 G_STRUCT_OFFSET (Inkscape::ApplicationClass, set_selection),
214 NULL, NULL,
215 sp_marshal_NONE__POINTER,
216 G_TYPE_NONE, 1,
217 G_TYPE_POINTER);
218 inkscape_signals[SET_EVENTCONTEXT] = g_signal_new ("set_eventcontext",
219 G_TYPE_FROM_CLASS (klass),
220 G_SIGNAL_RUN_FIRST,
221 G_STRUCT_OFFSET (Inkscape::ApplicationClass, set_eventcontext),
222 NULL, NULL,
223 sp_marshal_NONE__POINTER,
224 G_TYPE_NONE, 1,
225 G_TYPE_POINTER);
226 inkscape_signals[ACTIVATE_DESKTOP] = g_signal_new ("activate_desktop",
227 G_TYPE_FROM_CLASS (klass),
228 G_SIGNAL_RUN_FIRST,
229 G_STRUCT_OFFSET (Inkscape::ApplicationClass, activate_desktop),
230 NULL, NULL,
231 sp_marshal_NONE__POINTER,
232 G_TYPE_NONE, 1,
233 G_TYPE_POINTER);
234 inkscape_signals[DEACTIVATE_DESKTOP] = g_signal_new ("deactivate_desktop",
235 G_TYPE_FROM_CLASS (klass),
236 G_SIGNAL_RUN_FIRST,
237 G_STRUCT_OFFSET (Inkscape::ApplicationClass, deactivate_desktop),
238 NULL, NULL,
239 sp_marshal_NONE__POINTER,
240 G_TYPE_NONE, 1,
241 G_TYPE_POINTER);
242 inkscape_signals[SHUTDOWN_SIGNAL] = g_signal_new ("shut_down",
243 G_TYPE_FROM_CLASS (klass),
244 G_SIGNAL_RUN_FIRST,
245 G_STRUCT_OFFSET (Inkscape::ApplicationClass, shut_down),
246 NULL, NULL,
247 g_cclosure_marshal_VOID__VOID,
248 G_TYPE_NONE, 0);
249 inkscape_signals[DIALOGS_HIDE] = g_signal_new ("dialogs_hide",
250 G_TYPE_FROM_CLASS (klass),
251 G_SIGNAL_RUN_FIRST,
252 G_STRUCT_OFFSET (Inkscape::ApplicationClass, dialogs_hide),
253 NULL, NULL,
254 g_cclosure_marshal_VOID__VOID,
255 G_TYPE_NONE, 0);
256 inkscape_signals[DIALOGS_UNHIDE] = g_signal_new ("dialogs_unhide",
257 G_TYPE_FROM_CLASS (klass),
258 G_SIGNAL_RUN_FIRST,
259 G_STRUCT_OFFSET (Inkscape::ApplicationClass, dialogs_unhide),
260 NULL, NULL,
261 g_cclosure_marshal_VOID__VOID,
262 G_TYPE_NONE, 0);
263 inkscape_signals[EXTERNAL_CHANGE] = g_signal_new ("external_change",
264 G_TYPE_FROM_CLASS (klass),
265 G_SIGNAL_RUN_FIRST,
266 G_STRUCT_OFFSET (Inkscape::ApplicationClass, external_change),
267 NULL, NULL,
268 g_cclosure_marshal_VOID__VOID,
269 G_TYPE_NONE, 0);
271 object_class->dispose = inkscape_dispose;
273 klass->activate_desktop = inkscape_activate_desktop_private;
274 klass->deactivate_desktop = inkscape_deactivate_desktop_private;
275 }
277 #ifdef WIN32
278 typedef int uid_t;
279 #define getuid() 0
280 #endif
282 /**
283 * static gint inkscape_autosave(gpointer);
284 *
285 * Callback passed to g_timeout_add_seconds()
286 * Responsible for autosaving all open documents
287 */
288 static gint inkscape_autosave(gpointer)
289 {
290 if (inkscape->document_set.empty()) { // nothing to autosave
291 return TRUE;
292 }
293 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
295 // Use UID for separating autosave-documents between users if directory is multiuser
296 uid_t uid = getuid();
298 Glib::ustring autosave_dir;
299 {
300 Glib::ustring tmp = prefs->getString("/options/autosave/path");
301 if (!tmp.empty()) {
302 autosave_dir = tmp;
303 } else {
304 autosave_dir = Glib::get_tmp_dir();
305 }
306 }
308 GDir *autosave_dir_ptr = g_dir_open(autosave_dir.c_str(), 0, NULL);
309 if( !autosave_dir_ptr ){
310 g_warning("Cannot open autosave directory!");
311 return TRUE;
312 }
314 time_t sptime = time(NULL);
315 struct tm *sptm = localtime(&sptime);
316 gchar sptstr[256];
317 strftime(sptstr, 256, "%Y_%m_%d_%H_%M_%S", sptm);
319 gint autosave_max = prefs->getInt("/options/autosave/max", 10);
321 gint docnum = 0;
323 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Autosaving documents..."));
324 for (std::map<SPDocument*,int>::iterator iter = inkscape->document_set.begin();
325 iter != inkscape->document_set.end();
326 ++iter) {
328 SPDocument *doc = iter->first;
330 ++docnum;
332 Inkscape::XML::Node *repr = sp_document_repr_root(doc);
333 // g_debug("Document %d: \"%s\" %s", docnum, doc ? doc->name : "(null)", doc ? (doc->isModifiedSinceSave() ? "(dirty)" : "(clean)") : "(null)");
335 if (doc->isModifiedSinceSave()) {
336 gchar *oldest_autosave = 0;
337 const gchar *filename = 0;
338 struct stat sb;
339 time_t min_time = 0;
340 gint count = 0;
342 // Look for previous autosaves
343 gchar* baseName = g_strdup_printf( "inkscape-autosave-%d", uid );
344 g_dir_rewind(autosave_dir_ptr);
345 while( (filename = g_dir_read_name(autosave_dir_ptr)) != NULL ){
346 if ( strncmp(filename, baseName, strlen(baseName)) == 0 ){
347 gchar* full_path = g_build_filename( autosave_dir.c_str(), filename, NULL );
348 if ( g_stat(full_path, &sb) != -1 ) {
349 if ( difftime(sb.st_ctime, min_time) < 0 || min_time == 0 ){
350 min_time = sb.st_ctime;
351 if ( oldest_autosave ) {
352 g_free(oldest_autosave);
353 }
354 oldest_autosave = g_strdup(full_path);
355 }
356 count ++;
357 }
358 g_free(full_path);
359 }
360 }
362 // g_debug("%d previous autosaves exists. Max = %d", count, autosave_max);
364 // Have we reached the limit for number of autosaves?
365 if ( count >= autosave_max ){
366 // Remove the oldest file
367 if ( oldest_autosave ) {
368 unlink(oldest_autosave);
369 }
370 }
372 if ( oldest_autosave ) {
373 g_free(oldest_autosave);
374 oldest_autosave = 0;
375 }
378 // Set the filename we will actually save to
379 g_free(baseName);
380 baseName = g_strdup_printf("inkscape-autosave-%d-%s-%03d.svg", uid, sptstr, docnum);
381 gchar* full_path = g_build_filename(autosave_dir.c_str(), baseName, NULL);
382 g_free(baseName);
383 baseName = 0;
385 // g_debug("Filename: %s", full_path);
387 // Try to save the file
388 FILE *file = Inkscape::IO::fopen_utf8name(full_path, "w");
389 gchar *errortext = 0;
390 if (file) {
391 try{
392 sp_repr_save_stream(repr->document(), file, SP_SVG_NS_URI);
393 } catch (Inkscape::Extension::Output::no_extension_found &e) {
394 errortext = g_strdup(_("Autosave failed! Could not find inkscape extension to save document."));
395 } catch (Inkscape::Extension::Output::save_failed &e) {
396 gchar *safeUri = Inkscape::IO::sanitizeString(full_path);
397 errortext = g_strdup_printf(_("Autosave failed! File %s could not be saved."), safeUri);
398 g_free(safeUri);
399 }
400 fclose(file);
401 }
402 else {
403 gchar *safeUri = Inkscape::IO::sanitizeString(full_path);
404 errortext = g_strdup_printf(_("Autosave failed! File %s could not be saved."), safeUri);
405 g_free(safeUri);
406 }
408 if (errortext) {
409 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, errortext);
410 g_warning("%s", errortext);
411 g_free(errortext);
412 }
414 g_free(full_path);
415 }
416 }
417 g_dir_close(autosave_dir_ptr);
419 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Autosave complete."));
421 return TRUE;
422 }
424 void inkscape_autosave_init()
425 {
426 static guint32 autosave_timeout_id = 0;
427 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
429 // Turn off any previously initiated timeouts
430 if ( autosave_timeout_id ) {
431 g_source_remove(autosave_timeout_id);
432 autosave_timeout_id = 0;
433 }
435 // g_debug("options.autosave.enable = %d", prefs->getBool("/options/autosave/enable", true));
436 // Is autosave enabled?
437 if (!prefs->getBool("/options/autosave/enable", true)){
438 autosave_timeout_id = 0;
439 } else {
440 // Turn on autosave
441 guint32 timeout = prefs->getInt("/options/autosave/interval", 10) * 60;
442 // g_debug("options.autosave.interval = %d", prefs->getInt("/options/autosave/interval", 10));
443 #if GLIB_CHECK_VERSION(2,14,0)
444 autosave_timeout_id = g_timeout_add_seconds(timeout, inkscape_autosave, NULL);
445 #else
446 autosave_timeout_id = g_timeout_add(timeout * 1000, inkscape_autosave, NULL);
447 #endif
448 }
449 }
452 static void
453 inkscape_init (SPObject * object)
454 {
455 if (!inkscape) {
456 inkscape = (Inkscape::Application *) object;
457 } else {
458 g_assert_not_reached ();
459 }
461 new (&inkscape->document_set) std::map<SPDocument *, int>();
463 inkscape->menus = sp_repr_read_mem (_(menus_skeleton), MENUS_SKELETON_SIZE, NULL);
464 inkscape->desktops = NULL;
465 inkscape->dialogs_toggle = TRUE;
466 inkscape->mapalt = GDK_MOD1_MASK;
467 inkscape->trackalt = FALSE;
468 }
470 static void
471 inkscape_dispose (GObject *object)
472 {
473 Inkscape::Application *inkscape = (Inkscape::Application *) object;
475 g_assert (!inkscape->desktops);
477 Inkscape::Preferences::unload();
479 if (inkscape->menus) {
480 /* fixme: This is not the best place */
481 Inkscape::GC::release(inkscape->menus);
482 inkscape->menus = NULL;
483 }
485 inkscape->document_set.~map();
487 G_OBJECT_CLASS (parent_class)->dispose (object);
489 gtk_main_quit ();
490 }
493 void
494 inkscape_ref (void)
495 {
496 if (inkscape)
497 g_object_ref (G_OBJECT (inkscape));
498 }
501 void
502 inkscape_unref (void)
503 {
504 if (inkscape)
505 g_object_unref (G_OBJECT (inkscape));
506 }
508 /* returns the mask of the keyboard modifier to map to Alt, zero if no mapping */
509 /* Needs to be a guint because gdktypes.h does not define a 'no-modifier' value */
510 guint
511 inkscape_mapalt() {
512 return inkscape->mapalt;
513 }
515 /* Sets the keyboard modifer to map to Alt. Zero switches off mapping, as does '1', which is the default */
516 void inkscape_mapalt(guint maskvalue)
517 {
518 if(maskvalue<2 || maskvalue> 5 ){ /* MOD5 is the highest defined in gdktypes.h */
519 inkscape->mapalt=0;
520 }else{
521 inkscape->mapalt=(GDK_MOD1_MASK << (maskvalue-1));
522 }
523 }
525 guint
526 inkscape_trackalt() {
527 return inkscape->trackalt;
528 }
530 void inkscape_trackalt(guint trackvalue)
531 {
532 inkscape->trackalt = trackvalue;
533 }
536 static void
537 inkscape_activate_desktop_private (Inkscape::Application */*inkscape*/, SPDesktop *desktop)
538 {
539 desktop->set_active (true);
540 }
543 static void
544 inkscape_deactivate_desktop_private (Inkscape::Application */*inkscape*/, SPDesktop *desktop)
545 {
546 desktop->set_active (false);
547 }
550 /* fixme: This is EVIL, and belongs to main after all */
552 #define SP_INDENT 8
555 static void
556 inkscape_crash_handler (int /*signum*/)
557 {
558 using Inkscape::Debug::SimpleEvent;
559 using Inkscape::Debug::EventTracker;
560 using Inkscape::Debug::Logger;
562 static gint recursion = FALSE;
564 /*
565 * reset all signal handlers: any further crashes should just be allowed
566 * to crash normally.
567 * */
568 signal (SIGSEGV, segv_handler );
569 signal (SIGABRT, abrt_handler );
570 signal (SIGFPE, fpe_handler );
571 signal (SIGILL, ill_handler );
572 #ifndef WIN32
573 signal (SIGBUS, bus_handler );
574 #endif
576 /* Stop bizarre loops */
577 if (recursion) {
578 abort ();
579 }
580 recursion = TRUE;
582 EventTracker<SimpleEvent<Inkscape::Debug::Event::CORE> > tracker("crash");
583 tracker.set<SimpleEvent<> >("emergency-save");
585 fprintf(stderr, "\nEmergency save activated!\n");
587 time_t sptime = time (NULL);
588 struct tm *sptm = localtime (&sptime);
589 gchar sptstr[256];
590 strftime (sptstr, 256, "%Y_%m_%d_%H_%M_%S", sptm);
592 gint count = 0;
593 GSList *savednames = NULL;
594 GSList *failednames = NULL;
595 for (std::map<SPDocument*,int>::iterator iter = inkscape->document_set.begin();
596 iter != inkscape->document_set.end();
597 ++iter) {
598 SPDocument *doc = iter->first;
599 Inkscape::XML::Node *repr;
600 repr = sp_document_repr_root (doc);
601 if (doc->isModifiedSinceSave()) {
602 const gchar *docname, *d0, *d;
603 gchar n[64], c[1024];
604 FILE *file;
606 /* originally, the document name was retrieved from
607 * the sodipod:docname attribute */
608 docname = doc->name;
609 if (docname) {
610 /* fixme: Quick hack to remove emergency file suffix */
611 d0 = strrchr ((char*)docname, '.');
612 if (d0 && (d0 > docname)) {
613 d0 = strrchr ((char*)(d0 - 1), '.');
614 if (d0 && (d0 > docname)) {
615 d = d0;
616 while (isdigit (*d) || (*d == '.') || (*d == '_')) d += 1;
617 if (*d) {
618 memcpy (n, docname, MIN (d0 - docname - 1, 64));
619 n[63] = '\0';
620 docname = n;
621 }
622 }
623 }
624 }
626 if (!docname || !*docname) docname = "emergency";
627 // try saving to the profile location
628 g_snprintf (c, 1024, "%.256s.%s.%d.svg", docname, sptstr, count);
629 gchar * location = homedir_path(c);
630 Inkscape::IO::dump_fopen_call(location, "E");
631 file = Inkscape::IO::fopen_utf8name(location, "w");
632 g_free(location);
633 if (!file) {
634 // try saving to /tmp
635 g_snprintf (c, 1024, "/tmp/inkscape-%.256s.%s.%d.svg", docname, sptstr, count);
636 Inkscape::IO::dump_fopen_call(c, "G");
637 file = Inkscape::IO::fopen_utf8name(c, "w");
638 }
639 if (!file) {
640 // try saving to the current directory
641 g_snprintf (c, 1024, "inkscape-%.256s.%s.%d.svg", docname, sptstr, count);
642 Inkscape::IO::dump_fopen_call(c, "F");
643 file = Inkscape::IO::fopen_utf8name(c, "w");
644 }
645 if (file) {
646 sp_repr_save_stream (repr->document(), file, SP_SVG_NS_URI);
647 savednames = g_slist_prepend (savednames, g_strdup (c));
648 fclose (file);
649 } else {
650 failednames = g_slist_prepend (failednames, (doc->name) ? g_strdup (doc->name) : g_strdup (_("Untitled document")));
651 }
652 count++;
653 }
654 }
656 savednames = g_slist_reverse (savednames);
657 failednames = g_slist_reverse (failednames);
658 if (savednames) {
659 fprintf (stderr, "\nEmergency save document locations:\n");
660 for (GSList *l = savednames; l != NULL; l = l->next) {
661 fprintf (stderr, " %s\n", (gchar *) l->data);
662 }
663 }
664 if (failednames) {
665 fprintf (stderr, "\nFailed to do emergency save for documents:\n");
666 for (GSList *l = failednames; l != NULL; l = l->next) {
667 fprintf (stderr, " %s\n", (gchar *) l->data);
668 }
669 }
671 // do not save the preferences since they can be in a corrupted state
672 Inkscape::Preferences::unload(false);
674 fprintf (stderr, "Emergency save completed. Inkscape will close now.\n");
675 fprintf (stderr, "If you can reproduce this crash, please file a bug at www.inkscape.org\n");
676 fprintf (stderr, "with a detailed description of the steps leading to the crash, so we can fix it.\n");
678 /* Show nice dialog box */
680 char const *istr = _("Inkscape encountered an internal error and will close now.\n");
681 char const *sstr = _("Automatic backups of unsaved documents were done to the following locations:\n");
682 char const *fstr = _("Automatic backup of the following documents failed:\n");
683 gint nllen = strlen ("\n");
684 gint len = strlen (istr) + strlen (sstr) + strlen (fstr);
685 for (GSList *l = savednames; l != NULL; l = l->next) {
686 len = len + SP_INDENT + strlen ((gchar *) l->data) + nllen;
687 }
688 for (GSList *l = failednames; l != NULL; l = l->next) {
689 len = len + SP_INDENT + strlen ((gchar *) l->data) + nllen;
690 }
691 len += 1;
692 gchar *b = g_new (gchar, len);
693 gint pos = 0;
694 len = strlen (istr);
695 memcpy (b + pos, istr, len);
696 pos += len;
697 if (savednames) {
698 len = strlen (sstr);
699 memcpy (b + pos, sstr, len);
700 pos += len;
701 for (GSList *l = savednames; l != NULL; l = l->next) {
702 memset (b + pos, ' ', SP_INDENT);
703 pos += SP_INDENT;
704 len = strlen ((gchar *) l->data);
705 memcpy (b + pos, l->data, len);
706 pos += len;
707 memcpy (b + pos, "\n", nllen);
708 pos += nllen;
709 }
710 }
711 if (failednames) {
712 len = strlen (fstr);
713 memcpy (b + pos, fstr, len);
714 pos += len;
715 for (GSList *l = failednames; l != NULL; l = l->next) {
716 memset (b + pos, ' ', SP_INDENT);
717 pos += SP_INDENT;
718 len = strlen ((gchar *) l->data);
719 memcpy (b + pos, l->data, len);
720 pos += len;
721 memcpy (b + pos, "\n", nllen);
722 pos += nllen;
723 }
724 }
725 *(b + pos) = '\0';
727 if ( inkscape_get_instance() && inkscape_app_use_gui( inkscape_get_instance() ) ) {
728 GtkWidget *msgbox = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", b);
729 gtk_dialog_run (GTK_DIALOG (msgbox));
730 gtk_widget_destroy (msgbox);
731 }
732 else
733 {
734 g_message( "Error: %s", b );
735 }
736 g_free (b);
738 tracker.clear();
739 Logger::shutdown();
741 /* on exit, allow restored signal handler to take over and crash us */
742 }
746 void
747 inkscape_application_init (const gchar *argv0, gboolean use_gui)
748 {
749 inkscape = (Inkscape::Application *)g_object_new (SP_TYPE_INKSCAPE, NULL);
750 /* fixme: load application defaults */
752 segv_handler = signal (SIGSEGV, inkscape_crash_handler);
753 abrt_handler = signal (SIGABRT, inkscape_crash_handler);
754 fpe_handler = signal (SIGFPE, inkscape_crash_handler);
755 ill_handler = signal (SIGILL, inkscape_crash_handler);
756 #ifndef WIN32
757 bus_handler = signal (SIGBUS, inkscape_crash_handler);
758 #endif
760 inkscape->use_gui = use_gui;
761 inkscape->argv0 = g_strdup(argv0);
763 /* Load the preferences and menus */
764 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
765 prefs->load(use_gui, false);
766 inkscape_load_menus(inkscape);
767 sp_input_load_from_preferences();
769 /* set language for user interface according setting in preferences */
770 Glib::ustring ui_language = prefs->getString("/ui/language");
771 if(!ui_language.empty())
772 {
773 setenv("LANGUAGE", ui_language, 1);
774 }
776 /* DebugDialog redirection. On Linux, default to OFF, on Win32, default to ON.
777 * Use only if use_gui is enabled
778 */
779 #ifdef WIN32
780 #define DEFAULT_LOG_REDIRECT true
781 #else
782 #define DEFAULT_LOG_REDIRECT false
783 #endif
785 if (use_gui == TRUE && prefs->getBool("/dialogs/debug/redirect", DEFAULT_LOG_REDIRECT))
786 {
787 Inkscape::UI::Dialog::DebugDialog::getInstance()->captureLogMessages();
788 }
790 /* Check for global remapping of Alt key */
791 if (use_gui)
792 {
793 inkscape_mapalt(guint(prefs->getInt("/options/mapalt/value", 0)));
794 inkscape_trackalt(guint(prefs->getInt("/options/trackalt/value", 0)));
795 }
797 /* Initialize the extensions */
798 Inkscape::Extension::init();
800 inkscape_autosave_init();
802 return;
803 }
805 /**
806 * Returns the current Inkscape::Application global object
807 */
808 Inkscape::Application *
809 inkscape_get_instance()
810 {
811 return inkscape;
812 }
814 gboolean inkscape_app_use_gui( Inkscape::Application const * app )
815 {
816 return app->use_gui;
817 }
819 /**
820 * Menus management
821 *
822 */
823 bool inkscape_load_menus (Inkscape::Application */*inkscape*/)
824 {
825 gchar *fn = profile_path(MENUS_FILE);
826 gchar *menus_xml = NULL; gsize len = 0;
828 if (g_file_get_contents(fn, &menus_xml, &len, NULL)) {
829 // load the menus_xml file
830 INKSCAPE->menus = sp_repr_read_mem(menus_xml, len, NULL);
831 g_free(menus_xml);
832 if (INKSCAPE->menus) return true;
833 }
834 INKSCAPE->menus = sp_repr_read_mem(menus_skeleton, MENUS_SKELETON_SIZE, NULL);
835 if (INKSCAPE->menus) return true;
836 return false;
837 }
840 void
841 inkscape_selection_modified (Inkscape::Selection *selection, guint flags)
842 {
843 if (Inkscape::NSApplication::Application::getNewGui()) {
844 Inkscape::NSApplication::Editor::selectionModified (selection, flags);
845 return;
846 }
847 g_return_if_fail (selection != NULL);
849 if (DESKTOP_IS_ACTIVE (selection->desktop())) {
850 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[MODIFY_SELECTION], 0, selection, flags);
851 }
852 }
855 void
856 inkscape_selection_changed (Inkscape::Selection * selection)
857 {
858 if (Inkscape::NSApplication::Application::getNewGui()) {
859 Inkscape::NSApplication::Editor::selectionChanged (selection);
860 return;
861 }
862 g_return_if_fail (selection != NULL);
864 if (DESKTOP_IS_ACTIVE (selection->desktop())) {
865 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, selection);
866 }
867 }
869 void
870 inkscape_subselection_changed (SPDesktop *desktop)
871 {
872 if (Inkscape::NSApplication::Application::getNewGui()) {
873 Inkscape::NSApplication::Editor::subSelectionChanged (desktop);
874 return;
875 }
876 g_return_if_fail (desktop != NULL);
878 if (DESKTOP_IS_ACTIVE (desktop)) {
879 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SUBSELECTION], 0, desktop);
880 }
881 }
884 void
885 inkscape_selection_set (Inkscape::Selection * selection)
886 {
887 if (Inkscape::NSApplication::Application::getNewGui()) {
888 Inkscape::NSApplication::Editor::selectionSet (selection);
889 return;
890 }
891 g_return_if_fail (selection != NULL);
893 if (DESKTOP_IS_ACTIVE (selection->desktop())) {
894 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, selection);
895 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, selection);
896 }
897 }
900 void
901 inkscape_eventcontext_set (SPEventContext * eventcontext)
902 {
903 if (Inkscape::NSApplication::Application::getNewGui()) {
904 Inkscape::NSApplication::Editor::eventContextSet (eventcontext);
905 return;
906 }
907 g_return_if_fail (eventcontext != NULL);
908 g_return_if_fail (SP_IS_EVENT_CONTEXT (eventcontext));
910 if (DESKTOP_IS_ACTIVE (eventcontext->desktop)) {
911 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, eventcontext);
912 }
913 }
916 void
917 inkscape_add_desktop (SPDesktop * desktop)
918 {
919 g_return_if_fail (desktop != NULL);
921 if (Inkscape::NSApplication::Application::getNewGui())
922 {
923 Inkscape::NSApplication::Editor::addDesktop (desktop);
924 return;
925 }
926 g_return_if_fail (inkscape != NULL);
928 g_assert (!g_slist_find (inkscape->desktops, desktop));
930 inkscape->desktops = g_slist_prepend (inkscape->desktops, desktop);
932 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, desktop);
933 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, sp_desktop_event_context (desktop));
934 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, sp_desktop_selection (desktop));
935 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, sp_desktop_selection (desktop));
936 }
940 void
941 inkscape_remove_desktop (SPDesktop * desktop)
942 {
943 g_return_if_fail (desktop != NULL);
944 if (Inkscape::NSApplication::Application::getNewGui())
945 {
946 Inkscape::NSApplication::Editor::removeDesktop (desktop);
947 return;
948 }
949 g_return_if_fail (inkscape != NULL);
951 g_assert (g_slist_find (inkscape->desktops, desktop));
953 if (DESKTOP_IS_ACTIVE (desktop)) {
954 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DEACTIVATE_DESKTOP], 0, desktop);
955 if (inkscape->desktops->next != NULL) {
956 SPDesktop * new_desktop = (SPDesktop *) inkscape->desktops->next->data;
957 inkscape->desktops = g_slist_remove (inkscape->desktops, new_desktop);
958 inkscape->desktops = g_slist_prepend (inkscape->desktops, new_desktop);
959 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, new_desktop);
960 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, sp_desktop_event_context (new_desktop));
961 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, sp_desktop_selection (new_desktop));
962 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, sp_desktop_selection (new_desktop));
963 } else {
964 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, NULL);
965 if (sp_desktop_selection(desktop))
966 sp_desktop_selection(desktop)->clear();
967 }
968 }
970 inkscape->desktops = g_slist_remove (inkscape->desktops, desktop);
972 // if this was the last desktop, shut down the program
973 if (inkscape->desktops == NULL) {
974 inkscape_exit (inkscape);
975 }
976 }
980 void
981 inkscape_activate_desktop (SPDesktop * desktop)
982 {
983 g_return_if_fail (desktop != NULL);
984 if (Inkscape::NSApplication::Application::getNewGui())
985 {
986 Inkscape::NSApplication::Editor::activateDesktop (desktop);
987 return;
988 }
989 g_return_if_fail (inkscape != NULL);
991 if (DESKTOP_IS_ACTIVE (desktop)) {
992 return;
993 }
995 g_assert (g_slist_find (inkscape->desktops, desktop));
997 SPDesktop *current = (SPDesktop *) inkscape->desktops->data;
999 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DEACTIVATE_DESKTOP], 0, current);
1001 inkscape->desktops = g_slist_remove (inkscape->desktops, desktop);
1002 inkscape->desktops = g_slist_prepend (inkscape->desktops, desktop);
1004 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, desktop);
1005 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, sp_desktop_event_context (desktop));
1006 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, sp_desktop_selection (desktop));
1007 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, sp_desktop_selection (desktop));
1008 }
1011 /**
1012 * Resends ACTIVATE_DESKTOP for current desktop; needed when a new desktop has got its window that dialogs will transientize to
1013 */
1014 void
1015 inkscape_reactivate_desktop (SPDesktop * desktop)
1016 {
1017 g_return_if_fail (desktop != NULL);
1018 if (Inkscape::NSApplication::Application::getNewGui())
1019 {
1020 Inkscape::NSApplication::Editor::reactivateDesktop (desktop);
1021 return;
1022 }
1023 g_return_if_fail (inkscape != NULL);
1025 if (DESKTOP_IS_ACTIVE (desktop))
1026 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, desktop);
1027 }
1031 SPDesktop *
1032 inkscape_find_desktop_by_dkey (unsigned int dkey)
1033 {
1034 for (GSList *r = inkscape->desktops; r; r = r->next) {
1035 if (((SPDesktop *) r->data)->dkey == dkey)
1036 return ((SPDesktop *) r->data);
1037 }
1038 return NULL;
1039 }
1044 unsigned int
1045 inkscape_maximum_dkey()
1046 {
1047 unsigned int dkey = 0;
1049 for (GSList *r = inkscape->desktops; r; r = r->next) {
1050 if (((SPDesktop *) r->data)->dkey > dkey)
1051 dkey = ((SPDesktop *) r->data)->dkey;
1052 }
1054 return dkey;
1055 }
1059 SPDesktop *
1060 inkscape_next_desktop ()
1061 {
1062 SPDesktop *d = NULL;
1063 unsigned int dkey_current = ((SPDesktop *) inkscape->desktops->data)->dkey;
1065 if (dkey_current < inkscape_maximum_dkey()) {
1066 // find next existing
1067 for (unsigned int i = dkey_current + 1; i <= inkscape_maximum_dkey(); i++) {
1068 d = inkscape_find_desktop_by_dkey (i);
1069 if (d) {
1070 break;
1071 }
1072 }
1073 } else {
1074 // find first existing
1075 for (unsigned int i = 0; i <= inkscape_maximum_dkey(); i++) {
1076 d = inkscape_find_desktop_by_dkey (i);
1077 if (d) {
1078 break;
1079 }
1080 }
1081 }
1083 g_assert (d);
1085 return d;
1086 }
1090 SPDesktop *
1091 inkscape_prev_desktop ()
1092 {
1093 SPDesktop *d = NULL;
1094 unsigned int dkey_current = ((SPDesktop *) inkscape->desktops->data)->dkey;
1096 if (dkey_current > 0) {
1097 // find prev existing
1098 for (signed int i = dkey_current - 1; i >= 0; i--) {
1099 d = inkscape_find_desktop_by_dkey (i);
1100 if (d) {
1101 break;
1102 }
1103 }
1104 }
1105 if (!d) {
1106 // find last existing
1107 d = inkscape_find_desktop_by_dkey (inkscape_maximum_dkey());
1108 }
1110 g_assert (d);
1112 return d;
1113 }
1117 void
1118 inkscape_switch_desktops_next ()
1119 {
1120 inkscape_next_desktop()->presentWindow();
1121 }
1125 void
1126 inkscape_switch_desktops_prev ()
1127 {
1128 inkscape_prev_desktop()->presentWindow();
1129 }
1133 void
1134 inkscape_dialogs_hide ()
1135 {
1136 if (Inkscape::NSApplication::Application::getNewGui())
1137 Inkscape::NSApplication::Editor::hideDialogs();
1138 else
1139 {
1140 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DIALOGS_HIDE], 0);
1141 inkscape->dialogs_toggle = FALSE;
1142 }
1143 }
1147 void
1148 inkscape_dialogs_unhide ()
1149 {
1150 if (Inkscape::NSApplication::Application::getNewGui())
1151 Inkscape::NSApplication::Editor::unhideDialogs();
1152 else
1153 {
1154 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DIALOGS_UNHIDE], 0);
1155 inkscape->dialogs_toggle = TRUE;
1156 }
1157 }
1161 void
1162 inkscape_dialogs_toggle ()
1163 {
1164 if (inkscape->dialogs_toggle) {
1165 inkscape_dialogs_hide ();
1166 } else {
1167 inkscape_dialogs_unhide ();
1168 }
1169 }
1171 void
1172 inkscape_external_change ()
1173 {
1174 g_return_if_fail (inkscape != NULL);
1176 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[EXTERNAL_CHANGE], 0);
1177 }
1179 /**
1180 * fixme: These need probably signals too
1181 */
1182 void
1183 inkscape_add_document (SPDocument *document)
1184 {
1185 g_return_if_fail (document != NULL);
1187 if (!Inkscape::NSApplication::Application::getNewGui())
1188 {
1189 // try to insert the pair into the list
1190 if (!(inkscape->document_set.insert(std::make_pair(document, 1)).second)) {
1191 //insert failed, this key (document) is already in the list
1192 for (std::map<SPDocument*,int>::iterator iter = inkscape->document_set.begin();
1193 iter != inkscape->document_set.end();
1194 ++iter) {
1195 if (iter->first == document) {
1196 // found this document in list, increase its count
1197 iter->second ++;
1198 }
1199 }
1200 }
1201 }
1202 else
1203 {
1204 Inkscape::NSApplication::Editor::addDocument (document);
1205 }
1206 }
1209 // returns true if this was last reference to this document, so you can delete it
1210 bool
1211 inkscape_remove_document (SPDocument *document)
1212 {
1213 g_return_val_if_fail (document != NULL, false);
1215 if (!Inkscape::NSApplication::Application::getNewGui())
1216 {
1217 for (std::map<SPDocument*,int>::iterator iter = inkscape->document_set.begin();
1218 iter != inkscape->document_set.end();
1219 ++iter) {
1220 if (iter->first == document) {
1221 // found this document in list, decrease its count
1222 iter->second --;
1223 if (iter->second < 1) {
1224 // this was the last one, remove the pair from list
1225 inkscape->document_set.erase (iter);
1226 return true;
1227 } else {
1228 return false;
1229 }
1230 }
1231 }
1232 }
1233 else
1234 {
1235 Inkscape::NSApplication::Editor::removeDocument (document);
1236 }
1238 return false;
1239 }
1241 SPDesktop *
1242 inkscape_active_desktop (void)
1243 {
1244 if (Inkscape::NSApplication::Application::getNewGui())
1245 return Inkscape::NSApplication::Editor::getActiveDesktop();
1247 if (inkscape->desktops == NULL) {
1248 return NULL;
1249 }
1251 return (SPDesktop *) inkscape->desktops->data;
1252 }
1254 SPDocument *
1255 inkscape_active_document (void)
1256 {
1257 if (Inkscape::NSApplication::Application::getNewGui())
1258 return Inkscape::NSApplication::Editor::getActiveDocument();
1260 if (SP_ACTIVE_DESKTOP) {
1261 return sp_desktop_document (SP_ACTIVE_DESKTOP);
1262 }
1264 return NULL;
1265 }
1267 bool inkscape_is_sole_desktop_for_document(SPDesktop const &desktop) {
1268 SPDocument const* document = desktop.doc();
1269 if (!document) {
1270 return false;
1271 }
1272 for ( GSList *iter = inkscape->desktops ; iter ; iter = iter->next ) {
1273 SPDesktop *other_desktop=(SPDesktop *)iter->data;
1274 SPDocument *other_document=other_desktop->doc();
1275 if ( other_document == document && other_desktop != &desktop ) {
1276 return false;
1277 }
1278 }
1279 return true;
1280 }
1282 SPEventContext *
1283 inkscape_active_event_context (void)
1284 {
1285 if (SP_ACTIVE_DESKTOP) {
1286 return sp_desktop_event_context (SP_ACTIVE_DESKTOP);
1287 }
1289 return NULL;
1290 }
1294 /*#####################
1295 # HELPERS
1296 #####################*/
1298 void
1299 inkscape_refresh_display (Inkscape::Application *inkscape)
1300 {
1301 for (GSList *l = inkscape->desktops; l != NULL; l = l->next) {
1302 (static_cast<Inkscape::UI::View::View*>(l->data))->requestRedraw();
1303 }
1304 }
1307 /**
1308 * Handler for Inkscape's Exit verb. This emits the shutdown signal,
1309 * saves the preferences if appropriate, and quits.
1310 */
1311 void
1312 inkscape_exit (Inkscape::Application */*inkscape*/)
1313 {
1314 g_assert (INKSCAPE);
1316 //emit shutdown signal so that dialogs could remember layout
1317 g_signal_emit (G_OBJECT (INKSCAPE), inkscape_signals[SHUTDOWN_SIGNAL], 0);
1319 Inkscape::Preferences::unload();
1320 gtk_main_quit ();
1321 }
1323 char *
1324 homedir_path(const char *filename)
1325 {
1326 static const gchar *homedir = NULL;
1327 if (!homedir) {
1328 homedir = g_get_home_dir();
1329 }
1330 if (!homedir) {
1331 homedir = g_path_get_dirname(INKSCAPE->argv0);
1332 }
1333 return g_build_filename(homedir, filename, NULL);
1334 }
1337 /**
1338 * Get, or guess, or decide the location where the preferences.xml
1339 * file should be located.
1340 */
1341 gchar *
1342 profile_path(const char *filename)
1343 {
1344 static const gchar *prefdir = NULL;
1345 if (!prefdir) {
1346 #ifdef HAS_SHGetSpecialFolderLocation
1347 // prefer c:\Documents and Settings\UserName\Application Data\ to
1348 // c:\Documents and Settings\userName\;
1349 if (!prefdir) {
1350 ITEMIDLIST *pidl = 0;
1351 if ( SHGetSpecialFolderLocation( NULL, CSIDL_APPDATA, &pidl ) == NOERROR ) {
1352 gchar * utf8Path = NULL;
1354 if ( PrintWin32::is_os_wide() ) {
1355 wchar_t pathBuf[MAX_PATH+1];
1356 g_assert(sizeof(wchar_t) == sizeof(gunichar2));
1358 if ( SHGetPathFromIDListW( pidl, pathBuf ) ) {
1359 utf8Path = g_utf16_to_utf8( (gunichar2*)(&pathBuf[0]), -1, NULL, NULL, NULL );
1360 }
1361 } else {
1362 char pathBuf[MAX_PATH+1];
1364 if ( SHGetPathFromIDListA( pidl, pathBuf ) ) {
1365 utf8Path = g_filename_to_utf8( pathBuf, -1, NULL, NULL, NULL );
1366 }
1367 }
1369 if ( utf8Path ) {
1370 if (!g_utf8_validate(utf8Path, -1, NULL)) {
1371 g_warning( "SHGetPathFromIDList%c() resulted in invalid UTF-8", (PrintWin32::is_os_wide() ? 'W' : 'A') );
1372 g_free( utf8Path );
1373 utf8Path = 0;
1374 } else {
1375 prefdir = utf8Path;
1376 }
1377 }
1380 /* not compiling yet...
1382 // Remember to free the list pointer
1383 IMalloc * imalloc = 0;
1384 if ( SHGetMalloc(&imalloc) == NOERROR) {
1385 imalloc->lpVtbl->Free( imalloc, pidl );
1386 imalloc->lpVtbl->Release( imalloc );
1387 }
1388 */
1389 }
1391 if (prefdir) {
1392 prefdir = g_build_filename(prefdir, INKSCAPE_PROFILE_DIR, NULL);
1393 }
1394 }
1395 #endif
1396 if (!prefdir) {
1397 prefdir = g_build_filename(g_get_user_config_dir(), INKSCAPE_PROFILE_DIR, NULL);
1398 gchar * legacyDir = homedir_path(INKSCAPE_LEGACY_PROFILE_DIR);
1400 // TODO here is a point to hook in preference migration
1402 if ( !Inkscape::IO::file_test( prefdir, G_FILE_TEST_EXISTS ) && Inkscape::IO::file_test( legacyDir, G_FILE_TEST_EXISTS ) ) {
1403 prefdir = legacyDir;
1404 } else {
1405 g_free(legacyDir);
1406 legacyDir = 0;
1407 }
1408 }
1409 }
1410 return g_build_filename(prefdir, filename, NULL);
1411 }
1413 Inkscape::XML::Node *
1414 inkscape_get_menus (Inkscape::Application * inkscape)
1415 {
1416 Inkscape::XML::Node *repr = inkscape->menus->root();
1417 g_assert (!(strcmp (repr->name(), "inkscape")));
1418 return repr->firstChild();
1419 }
1421 void
1422 inkscape_get_all_desktops(std::list< SPDesktop* >& listbuf)
1423 {
1424 for(GSList* l = inkscape->desktops; l != NULL; l = l->next) {
1425 listbuf.push_back(static_cast< SPDesktop* >(l->data));
1426 }
1427 }
1429 /*
1430 Local Variables:
1431 mode:c++
1432 c-file-style:"stroustrup"
1433 c-file-offsets:((innamespace . 0)(inline-open . 0))
1434 indent-tabs-mode:nil
1435 fill-column:99
1436 End:
1437 */
1438 // vim: expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :