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 "application/application.h"
53 #include "application/editor.h"
54 #include "preferences.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 "prefs-utils.h"
64 #include "xml/repr.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 static bool inkscape_init_config (Inkscape::XML::Document *doc, const gchar *config_name, const gchar *skeleton,
111 unsigned int skel_size,
112 const gchar *e_mkdir,
113 const gchar *e_notdir,
114 const gchar *e_ccf,
115 const gchar *e_cwf,
116 const gchar *warn);
118 struct Inkscape::Application {
119 GObject object;
120 Inkscape::XML::Document *menus;
121 std::multiset<SPDocument *> document_set;
122 GSList *documents;
123 GSList *desktops;
124 gchar *argv0;
125 gboolean dialogs_toggle;
126 gboolean use_gui; // may want to consider a virtual function
127 // for overriding things like the warning dlg's
128 guint mapalt;
129 };
131 struct Inkscape::ApplicationClass {
132 GObjectClass object_class;
134 /* Signals */
135 void (* change_selection) (Inkscape::Application * inkscape, Inkscape::Selection * selection);
136 void (* change_subselection) (Inkscape::Application * inkscape, SPDesktop *desktop);
137 void (* modify_selection) (Inkscape::Application * inkscape, Inkscape::Selection * selection, guint flags);
138 void (* set_selection) (Inkscape::Application * inkscape, Inkscape::Selection * selection);
139 void (* set_eventcontext) (Inkscape::Application * inkscape, SPEventContext * eventcontext);
140 void (* activate_desktop) (Inkscape::Application * inkscape, SPDesktop * desktop);
141 void (* deactivate_desktop) (Inkscape::Application * inkscape, SPDesktop * desktop);
142 void (* destroy_document) (Inkscape::Application *inkscape, SPDocument *doc);
143 void (* color_set) (Inkscape::Application *inkscape, SPColor *color, double opacity);
144 void (* shut_down) (Inkscape::Application *inkscape);
145 void (* dialogs_hide) (Inkscape::Application *inkscape);
146 void (* dialogs_unhide) (Inkscape::Application *inkscape);
147 void (* external_change) (Inkscape::Application *inkscape);
148 };
150 static GObjectClass * parent_class;
151 static guint inkscape_signals[LAST_SIGNAL] = {0};
153 static void (* segv_handler) (int) = SIG_DFL;
154 static void (* abrt_handler) (int) = SIG_DFL;
155 static void (* fpe_handler) (int) = SIG_DFL;
156 static void (* ill_handler) (int) = SIG_DFL;
157 static void (* bus_handler) (int) = SIG_DFL;
159 #ifdef WIN32
160 #define INKSCAPE_PROFILE_DIR "Inkscape"
161 #else
162 #define INKSCAPE_PROFILE_DIR ".inkscape"
163 #endif
165 #define MENUS_FILE "menus.xml"
168 /**
169 * Retrieves the GType for the Inkscape Application object.
170 */
171 GType
172 inkscape_get_type (void)
173 {
174 static GType type = 0;
175 if (!type) {
176 GTypeInfo info = {
177 sizeof (Inkscape::ApplicationClass),
178 NULL, NULL,
179 (GClassInitFunc) inkscape_class_init,
180 NULL, NULL,
181 sizeof (Inkscape::Application),
182 4,
183 (GInstanceInitFunc) inkscape_init,
184 NULL
185 };
186 type = g_type_register_static (G_TYPE_OBJECT, "Inkscape_Application", &info, (GTypeFlags)0);
187 }
188 return type;
189 }
192 /**
193 * Initializes the inkscape class, registering all of its signal handlers
194 * and virtual functions
195 */
196 static void
197 inkscape_class_init (Inkscape::ApplicationClass * klass)
198 {
199 GObjectClass * object_class;
201 object_class = (GObjectClass *) klass;
203 parent_class = (GObjectClass *)g_type_class_peek_parent (klass);
205 inkscape_signals[MODIFY_SELECTION] = g_signal_new ("modify_selection",
206 G_TYPE_FROM_CLASS (klass),
207 G_SIGNAL_RUN_FIRST,
208 G_STRUCT_OFFSET (Inkscape::ApplicationClass, modify_selection),
209 NULL, NULL,
210 sp_marshal_NONE__POINTER_UINT,
211 G_TYPE_NONE, 2,
212 G_TYPE_POINTER, G_TYPE_UINT);
213 inkscape_signals[CHANGE_SELECTION] = g_signal_new ("change_selection",
214 G_TYPE_FROM_CLASS (klass),
215 G_SIGNAL_RUN_FIRST,
216 G_STRUCT_OFFSET (Inkscape::ApplicationClass, change_selection),
217 NULL, NULL,
218 sp_marshal_NONE__POINTER,
219 G_TYPE_NONE, 1,
220 G_TYPE_POINTER);
221 inkscape_signals[CHANGE_SUBSELECTION] = g_signal_new ("change_subselection",
222 G_TYPE_FROM_CLASS (klass),
223 G_SIGNAL_RUN_FIRST,
224 G_STRUCT_OFFSET (Inkscape::ApplicationClass, change_subselection),
225 NULL, NULL,
226 sp_marshal_NONE__POINTER,
227 G_TYPE_NONE, 1,
228 G_TYPE_POINTER);
229 inkscape_signals[SET_SELECTION] = g_signal_new ("set_selection",
230 G_TYPE_FROM_CLASS (klass),
231 G_SIGNAL_RUN_FIRST,
232 G_STRUCT_OFFSET (Inkscape::ApplicationClass, set_selection),
233 NULL, NULL,
234 sp_marshal_NONE__POINTER,
235 G_TYPE_NONE, 1,
236 G_TYPE_POINTER);
237 inkscape_signals[SET_EVENTCONTEXT] = g_signal_new ("set_eventcontext",
238 G_TYPE_FROM_CLASS (klass),
239 G_SIGNAL_RUN_FIRST,
240 G_STRUCT_OFFSET (Inkscape::ApplicationClass, set_eventcontext),
241 NULL, NULL,
242 sp_marshal_NONE__POINTER,
243 G_TYPE_NONE, 1,
244 G_TYPE_POINTER);
245 inkscape_signals[ACTIVATE_DESKTOP] = g_signal_new ("activate_desktop",
246 G_TYPE_FROM_CLASS (klass),
247 G_SIGNAL_RUN_FIRST,
248 G_STRUCT_OFFSET (Inkscape::ApplicationClass, activate_desktop),
249 NULL, NULL,
250 sp_marshal_NONE__POINTER,
251 G_TYPE_NONE, 1,
252 G_TYPE_POINTER);
253 inkscape_signals[DEACTIVATE_DESKTOP] = g_signal_new ("deactivate_desktop",
254 G_TYPE_FROM_CLASS (klass),
255 G_SIGNAL_RUN_FIRST,
256 G_STRUCT_OFFSET (Inkscape::ApplicationClass, deactivate_desktop),
257 NULL, NULL,
258 sp_marshal_NONE__POINTER,
259 G_TYPE_NONE, 1,
260 G_TYPE_POINTER);
261 inkscape_signals[SHUTDOWN_SIGNAL] = g_signal_new ("shut_down",
262 G_TYPE_FROM_CLASS (klass),
263 G_SIGNAL_RUN_FIRST,
264 G_STRUCT_OFFSET (Inkscape::ApplicationClass, shut_down),
265 NULL, NULL,
266 g_cclosure_marshal_VOID__VOID,
267 G_TYPE_NONE, 0);
268 inkscape_signals[DIALOGS_HIDE] = g_signal_new ("dialogs_hide",
269 G_TYPE_FROM_CLASS (klass),
270 G_SIGNAL_RUN_FIRST,
271 G_STRUCT_OFFSET (Inkscape::ApplicationClass, dialogs_hide),
272 NULL, NULL,
273 g_cclosure_marshal_VOID__VOID,
274 G_TYPE_NONE, 0);
275 inkscape_signals[DIALOGS_UNHIDE] = g_signal_new ("dialogs_unhide",
276 G_TYPE_FROM_CLASS (klass),
277 G_SIGNAL_RUN_FIRST,
278 G_STRUCT_OFFSET (Inkscape::ApplicationClass, dialogs_unhide),
279 NULL, NULL,
280 g_cclosure_marshal_VOID__VOID,
281 G_TYPE_NONE, 0);
282 inkscape_signals[EXTERNAL_CHANGE] = g_signal_new ("external_change",
283 G_TYPE_FROM_CLASS (klass),
284 G_SIGNAL_RUN_FIRST,
285 G_STRUCT_OFFSET (Inkscape::ApplicationClass, external_change),
286 NULL, NULL,
287 g_cclosure_marshal_VOID__VOID,
288 G_TYPE_NONE, 0);
290 object_class->dispose = inkscape_dispose;
292 klass->activate_desktop = inkscape_activate_desktop_private;
293 klass->deactivate_desktop = inkscape_deactivate_desktop_private;
294 }
296 #ifdef WIN32
297 typedef int uid_t;
298 #define getuid() 0
299 #endif
301 /**
302 * static gint inkscape_autosave(gpointer);
303 *
304 * Callback passed to g_timeout_add_seconds()
305 * Responsible for autosaving all open documents
306 */
307 static gint inkscape_autosave(gpointer)
308 {
309 // Use UID for separating autosave-documents between users if directory is multiuser
310 uid_t uid = getuid();
312 Glib::ustring autosave_dir;
313 {
314 gchar const* tmp = prefs_get_string_attribute("options.autosave", "path");
315 if ( tmp ) {
316 autosave_dir = tmp;
317 } else {
318 autosave_dir = Glib::get_tmp_dir();
319 }
320 }
322 GDir *autosave_dir_ptr = g_dir_open(autosave_dir.c_str(), 0, NULL);
323 if( !autosave_dir_ptr ){
324 g_warning("Cannot open autosave directory!");
325 return TRUE;
326 }
328 time_t sptime = time(NULL);
329 struct tm *sptm = localtime(&sptime);
330 gchar sptstr[256];
331 strftime(sptstr, 256, "%Y_%m_%d_%H_%M_%S", sptm);
333 gint autosave_max = prefs_get_int_attribute("options.autosave", "max", 10);
335 gint docnum = 0;
337 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Autosaving documents..."));
338 for (GSList *docList = inkscape->documents; docList; docList = docList->next) {
339 ++docnum;
341 // TODO replace this with SP_DOCUMENT() when linking issues are addressed:
342 SPDocument *doc = static_cast<SPDocument *>(docList->data);
343 Inkscape::XML::Node *repr = sp_document_repr_root(doc);
344 // g_debug("Document %d: \"%s\" %s", docnum, doc ? doc->name : "(null)", doc ? (doc->isModifiedSinceSave() ? "(dirty)" : "(clean)") : "(null)");
346 if (doc->isModifiedSinceSave()) {
347 gchar *oldest_autosave = 0;
348 const gchar *filename = 0;
349 struct stat sb;
350 time_t min_time = 0;
351 gint count = 0;
353 // Look for previous autosaves
354 gchar* baseName = g_strdup_printf( "inkscape-autosave-%d", uid );
355 g_dir_rewind(autosave_dir_ptr);
356 while( (filename = g_dir_read_name(autosave_dir_ptr)) != NULL ){
357 if ( strncmp(filename, baseName, strlen(baseName)) == 0 ){
358 gchar* full_path = g_build_filename( autosave_dir.c_str(), filename, NULL );
359 if ( g_stat(full_path, &sb) != -1 ) {
360 if ( difftime(sb.st_ctime, min_time) < 0 || min_time == 0 ){
361 min_time = sb.st_ctime;
362 if ( oldest_autosave ) {
363 g_free(oldest_autosave);
364 }
365 oldest_autosave = g_strdup(full_path);
366 }
367 count ++;
368 }
369 g_free(full_path);
370 }
371 }
373 // g_debug("%d previous autosaves exists. Max = %d", count, autosave_max);
375 // Have we reached the limit for number of autosaves?
376 if ( count >= autosave_max ){
377 // Remove the oldest file
378 if ( oldest_autosave ) {
379 unlink(oldest_autosave);
380 }
381 }
383 if ( oldest_autosave ) {
384 g_free(oldest_autosave);
385 oldest_autosave = 0;
386 }
389 // Set the filename we will actually save to
390 g_free(baseName);
391 baseName = g_strdup_printf("inkscape-autosave-%d-%s-%03d.svg", uid, sptstr, docnum);
392 gchar* full_path = g_build_filename(autosave_dir.c_str(), baseName, NULL);
393 g_free(baseName);
394 baseName = 0;
396 // g_debug("Filename: %s", full_path);
398 // Try to save the file
399 FILE *file = Inkscape::IO::fopen_utf8name(full_path, "w");
400 gchar *errortext = 0;
401 if (file) {
402 try{
403 sp_repr_save_stream(repr->document(), file, SP_SVG_NS_URI);
404 } catch (Inkscape::Extension::Output::no_extension_found &e) {
405 errortext = g_strdup(_("Autosave failed! Could not find inkscape extension to save document."));
406 } catch (Inkscape::Extension::Output::save_failed &e) {
407 gchar *safeUri = Inkscape::IO::sanitizeString(full_path);
408 errortext = g_strdup_printf(_("Autosave failed! File %s could not be saved."), safeUri);
409 g_free(safeUri);
410 }
411 fclose(file);
412 }
413 else {
414 gchar *safeUri = Inkscape::IO::sanitizeString(full_path);
415 errortext = g_strdup_printf(_("Autosave failed! File %s could not be saved."), safeUri);
416 g_free(safeUri);
417 }
419 if (errortext) {
420 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, errortext);
421 g_warning("%s", errortext);
422 g_free(errortext);
423 }
425 g_free(full_path);
426 }
427 }
428 g_dir_close(autosave_dir_ptr);
430 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Autosave complete."));
432 return TRUE;
433 }
435 void inkscape_autosave_init()
436 {
437 static guint32 autosave_timeout_id = 0;
439 // Turn off any previously initiated timeouts
440 if ( autosave_timeout_id ) {
441 g_source_remove(autosave_timeout_id);
442 autosave_timeout_id = 0;
443 }
445 // g_debug("options.autosave.enable = %lld", prefs_get_int_attribute_limited("options.autosave", "enable", 1, 0, 1));
446 // Is autosave enabled?
447 if( prefs_get_int_attribute_limited("options.autosave", "enable", 1, 0, 1) != 1 ){
448 autosave_timeout_id = 0;
449 } else {
450 // Turn on autosave
451 guint32 timeout = prefs_get_int_attribute("options.autosave", "interval", 10) * 60;
452 // g_debug("options.autosave.interval = %lld", prefs_get_int_attribute("options.autosave", "interval", 10));
453 #if GLIB_CHECK_VERSION(2,14,0)
454 autosave_timeout_id = g_timeout_add_seconds(timeout, inkscape_autosave, NULL);
455 #else
456 autosave_timeout_id = g_timeout_add(timeout * 1000, inkscape_autosave, NULL);
457 #endif
458 }
459 }
462 static void
463 inkscape_init (SPObject * object)
464 {
465 if (!inkscape) {
466 inkscape = (Inkscape::Application *) object;
467 } else {
468 g_assert_not_reached ();
469 }
471 new (&inkscape->document_set) std::multiset<SPDocument *>();
473 inkscape->menus = sp_repr_read_mem (_(menus_skeleton), MENUS_SKELETON_SIZE, NULL);
475 inkscape->documents = NULL;
476 inkscape->desktops = NULL;
478 inkscape->dialogs_toggle = TRUE;
480 inkscape->mapalt=GDK_MOD1_MASK;
481 }
483 static void
484 inkscape_dispose (GObject *object)
485 {
486 Inkscape::Application *inkscape = (Inkscape::Application *) object;
488 while (inkscape->documents) {
489 // we don't otherwise unref, so why here?
490 sp_document_unref((SPDocument *)inkscape->documents->data);
491 }
493 g_assert (!inkscape->desktops);
495 Inkscape::Preferences::save();
497 if (inkscape->menus) {
498 /* fixme: This is not the best place */
499 Inkscape::GC::release(inkscape->menus);
500 inkscape->menus = NULL;
501 }
503 inkscape->document_set.~multiset();
505 G_OBJECT_CLASS (parent_class)->dispose (object);
507 gtk_main_quit ();
508 }
511 void
512 inkscape_ref (void)
513 {
514 if (inkscape)
515 g_object_ref (G_OBJECT (inkscape));
516 }
519 void
520 inkscape_unref (void)
521 {
522 if (inkscape)
523 g_object_unref (G_OBJECT (inkscape));
524 }
526 /* returns the mask of the keyboard modifier to map to Alt, zero if no mapping */
527 /* Needs to be a guint because gdktypes.h does not define a 'no-modifier' value */
528 guint
529 inkscape_mapalt() {
530 return inkscape->mapalt;
531 }
533 /* Sets the keyboard modifer to map to Alt. Zero switches off mapping, as does '1', which is the default */
534 void inkscape_mapalt(guint maskvalue)
535 {
536 if(maskvalue<2 || maskvalue> 5 ){ /* MOD5 is the highest defined in gdktypes.h */
537 inkscape->mapalt=0;
538 }else{
539 inkscape->mapalt=(GDK_MOD1_MASK << (maskvalue-1));
540 }
541 }
543 static void
544 inkscape_activate_desktop_private (Inkscape::Application */*inkscape*/, SPDesktop *desktop)
545 {
546 desktop->set_active (true);
547 }
550 static void
551 inkscape_deactivate_desktop_private (Inkscape::Application */*inkscape*/, SPDesktop *desktop)
552 {
553 desktop->set_active (false);
554 }
557 /* fixme: This is EVIL, and belongs to main after all */
559 #define SP_INDENT 8
562 static void
563 inkscape_crash_handler (int /*signum*/)
564 {
565 using Inkscape::Debug::SimpleEvent;
566 using Inkscape::Debug::EventTracker;
567 using Inkscape::Debug::Logger;
569 static gint recursion = FALSE;
571 /*
572 * reset all signal handlers: any further crashes should just be allowed
573 * to crash normally.
574 * */
575 signal (SIGSEGV, segv_handler );
576 signal (SIGABRT, abrt_handler );
577 signal (SIGFPE, fpe_handler );
578 signal (SIGILL, ill_handler );
579 #ifndef WIN32
580 signal (SIGBUS, bus_handler );
581 #endif
583 /* Stop bizarre loops */
584 if (recursion) {
585 abort ();
586 }
587 recursion = TRUE;
589 EventTracker<SimpleEvent<Inkscape::Debug::Event::CORE> > tracker("crash");
590 tracker.set<SimpleEvent<> >("emergency-save");
592 fprintf(stderr, "\nEmergency save activated!\n");
594 time_t sptime = time (NULL);
595 struct tm *sptm = localtime (&sptime);
596 gchar sptstr[256];
597 strftime (sptstr, 256, "%Y_%m_%d_%H_%M_%S", sptm);
599 gint count = 0;
600 GSList *savednames = NULL;
601 GSList *failednames = NULL;
602 for (GSList *l = inkscape->documents; l != NULL; l = l->next) {
603 SPDocument *doc;
604 Inkscape::XML::Node *repr;
605 doc = (SPDocument *) l->data;
606 repr = sp_document_repr_root (doc);
607 if (doc->isModifiedSinceSave()) {
608 const gchar *docname, *d0, *d;
609 gchar n[64], c[1024];
610 FILE *file;
612 /* originally, the document name was retrieved from
613 * the sodipod:docname attribute */
614 docname = doc->name;
615 if (docname) {
616 /* fixme: Quick hack to remove emergency file suffix */
617 d0 = strrchr ((char*)docname, '.');
618 if (d0 && (d0 > docname)) {
619 d0 = strrchr ((char*)(d0 - 1), '.');
620 if (d0 && (d0 > docname)) {
621 d = d0;
622 while (isdigit (*d) || (*d == '.') || (*d == '_')) d += 1;
623 if (*d) {
624 memcpy (n, docname, MIN (d0 - docname - 1, 64));
625 n[63] = '\0';
626 docname = n;
627 }
628 }
629 }
630 }
632 if (!docname || !*docname) docname = "emergency";
633 // try saving to the profile location
634 g_snprintf (c, 1024, "%.256s.%s.%d", docname, sptstr, count);
635 gchar * location = homedir_path(c);
636 Inkscape::IO::dump_fopen_call(location, "E");
637 file = Inkscape::IO::fopen_utf8name(location, "w");
638 g_free(location);
639 if (!file) {
640 // try saving to /tmp
641 g_snprintf (c, 1024, "/tmp/inkscape-%.256s.%s.%d", docname, sptstr, count);
642 Inkscape::IO::dump_fopen_call(c, "G");
643 file = Inkscape::IO::fopen_utf8name(c, "w");
644 }
645 if (!file) {
646 // try saving to the current directory
647 g_snprintf (c, 1024, "inkscape-%.256s.%s.%d", docname, sptstr, count);
648 Inkscape::IO::dump_fopen_call(c, "F");
649 file = Inkscape::IO::fopen_utf8name(c, "w");
650 }
651 if (file) {
652 sp_repr_save_stream (repr->document(), file, SP_SVG_NS_URI);
653 savednames = g_slist_prepend (savednames, g_strdup (c));
654 fclose (file);
655 } else {
656 failednames = g_slist_prepend (failednames, (doc->name) ? g_strdup (doc->name) : g_strdup (_("Untitled document")));
657 }
658 count++;
659 }
660 }
662 savednames = g_slist_reverse (savednames);
663 failednames = g_slist_reverse (failednames);
664 if (savednames) {
665 fprintf (stderr, "\nEmergency save document locations:\n");
666 for (GSList *l = savednames; l != NULL; l = l->next) {
667 fprintf (stderr, " %s\n", (gchar *) l->data);
668 }
669 }
670 if (failednames) {
671 fprintf (stderr, "\nFailed to do emergency save for documents:\n");
672 for (GSList *l = failednames; l != NULL; l = l->next) {
673 fprintf (stderr, " %s\n", (gchar *) l->data);
674 }
675 }
677 Inkscape::Preferences::save();
679 fprintf (stderr, "Emergency save completed. Inkscape will close now.\n");
680 fprintf (stderr, "If you can reproduce this crash, please file a bug at www.inkscape.org\n");
681 fprintf (stderr, "with a detailed description of the steps leading to the crash, so we can fix it.\n");
683 /* Show nice dialog box */
685 char const *istr = _("Inkscape encountered an internal error and will close now.\n");
686 char const *sstr = _("Automatic backups of unsaved documents were done to the following locations:\n");
687 char const *fstr = _("Automatic backup of the following documents failed:\n");
688 gint nllen = strlen ("\n");
689 gint len = strlen (istr) + strlen (sstr) + strlen (fstr);
690 for (GSList *l = savednames; l != NULL; l = l->next) {
691 len = len + SP_INDENT + strlen ((gchar *) l->data) + nllen;
692 }
693 for (GSList *l = failednames; l != NULL; l = l->next) {
694 len = len + SP_INDENT + strlen ((gchar *) l->data) + nllen;
695 }
696 len += 1;
697 gchar *b = g_new (gchar, len);
698 gint pos = 0;
699 len = strlen (istr);
700 memcpy (b + pos, istr, len);
701 pos += len;
702 if (savednames) {
703 len = strlen (sstr);
704 memcpy (b + pos, sstr, len);
705 pos += len;
706 for (GSList *l = savednames; l != NULL; l = l->next) {
707 memset (b + pos, ' ', SP_INDENT);
708 pos += SP_INDENT;
709 len = strlen ((gchar *) l->data);
710 memcpy (b + pos, l->data, len);
711 pos += len;
712 memcpy (b + pos, "\n", nllen);
713 pos += nllen;
714 }
715 }
716 if (failednames) {
717 len = strlen (fstr);
718 memcpy (b + pos, fstr, len);
719 pos += len;
720 for (GSList *l = failednames; l != NULL; l = l->next) {
721 memset (b + pos, ' ', SP_INDENT);
722 pos += SP_INDENT;
723 len = strlen ((gchar *) l->data);
724 memcpy (b + pos, l->data, len);
725 pos += len;
726 memcpy (b + pos, "\n", nllen);
727 pos += nllen;
728 }
729 }
730 *(b + pos) = '\0';
732 if ( inkscape_get_instance() && inkscape_app_use_gui( inkscape_get_instance() ) ) {
733 GtkWidget *msgbox = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", b);
734 gtk_dialog_run (GTK_DIALOG (msgbox));
735 gtk_widget_destroy (msgbox);
736 }
737 else
738 {
739 g_message( "Error: %s", b );
740 }
741 g_free (b);
743 tracker.clear();
744 Logger::shutdown();
746 /* on exit, allow restored signal handler to take over and crash us */
747 }
751 void
752 inkscape_application_init (const gchar *argv0, gboolean use_gui)
753 {
754 inkscape = (Inkscape::Application *)g_object_new (SP_TYPE_INKSCAPE, NULL);
755 /* fixme: load application defaults */
757 segv_handler = signal (SIGSEGV, inkscape_crash_handler);
758 abrt_handler = signal (SIGABRT, inkscape_crash_handler);
759 fpe_handler = signal (SIGFPE, inkscape_crash_handler);
760 ill_handler = signal (SIGILL, inkscape_crash_handler);
761 #ifndef WIN32
762 bus_handler = signal (SIGBUS, inkscape_crash_handler);
763 #endif
765 inkscape->use_gui = use_gui;
766 inkscape->argv0 = g_strdup(argv0);
768 /* Attempt to load the preferences, and set the save_preferences flag to TRUE
769 if we could, or FALSE if we couldn't */
770 Inkscape::Preferences::load();
771 inkscape_load_menus(inkscape);
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_get_int_attribute("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_get_int_attribute("options.mapalt","value",0)));
791 }
793 /* Initialize the extensions */
794 Inkscape::Extension::init();
796 inkscape_autosave_init();
798 return;
799 }
801 /**
802 * Returns the current Inkscape::Application global object
803 */
804 Inkscape::Application *
805 inkscape_get_instance()
806 {
807 return inkscape;
808 }
810 gboolean inkscape_app_use_gui( Inkscape::Application const * app )
811 {
812 return app->use_gui;
813 }
815 /**
816 * Preference management
817 * We use '.' as separator
818 *
819 * Returns TRUE if the config file was successfully loaded, FALSE if not.
820 */
821 bool
822 inkscape_load_config (const gchar *filename, Inkscape::XML::Document *config, const gchar *skeleton,
823 unsigned int skel_size, const gchar *e_notreg, const gchar *e_notxml,
824 const gchar *e_notsp, const gchar *warn)
825 {
826 gchar *fn = profile_path(filename);
827 if (!Inkscape::IO::file_test(fn, G_FILE_TEST_EXISTS)) {
828 bool result;
829 /* No such file */
830 result = inkscape_init_config (config, filename, skeleton,
831 skel_size,
832 _("Cannot create directory %s.\n%s"),
833 _("%s is not a valid directory.\n%s"),
834 _("Cannot create file %s.\n%s"),
835 _("Cannot write file %s.\n%s"),
836 _("Although Inkscape will run, it will use default settings,\n"
837 "and any changes made in preferences will not be saved."));
838 g_free (fn);
839 return result;
840 }
842 if (!Inkscape::IO::file_test(fn, G_FILE_TEST_IS_REGULAR)) {
843 /* Not a regular file */
844 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
845 GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_notreg, safeFn, warn);
846 gtk_dialog_run (GTK_DIALOG (w));
847 gtk_widget_destroy (w);
848 g_free(safeFn);
849 g_free (fn);
850 return false;
851 }
853 Inkscape::XML::Document *doc = sp_repr_read_file (fn, NULL);
854 if (doc == NULL) {
855 /* Not an valid xml file */
856 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
857 GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_notxml, safeFn, warn);
858 gtk_dialog_run (GTK_DIALOG (w));
859 gtk_widget_destroy (w);
860 g_free(safeFn);
861 g_free (fn);
862 return false;
863 }
865 Inkscape::XML::Node *root = doc->root();
866 if (strcmp (root->name(), "inkscape")) {
867 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
868 GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_notsp, safeFn, warn);
869 gtk_dialog_run (GTK_DIALOG (w));
870 gtk_widget_destroy (w);
871 Inkscape::GC::release(doc);
872 g_free(safeFn);
873 g_free (fn);
874 return false;
875 }
877 /** \todo this is a hack, need to figure out how to get
878 * a reasonable merge working with the menus.xml file */
879 if (skel_size == MENUS_SKELETON_SIZE) {
880 if (INKSCAPE)
881 INKSCAPE->menus = doc;
882 doc = config;
883 } else {
884 config->root()->mergeFrom(doc->root(), "id");
885 }
887 Inkscape::GC::release(doc);
888 g_free (fn);
889 return true;
890 }
892 /**
893 * Menus management
894 *
895 */
896 bool
897 inkscape_load_menus (Inkscape::Application *inkscape)
898 {
899 gchar *fn = profile_path(MENUS_FILE);
900 bool retval = false;
901 if (Inkscape::IO::file_test(fn, G_FILE_TEST_EXISTS)) {
902 retval = inkscape_load_config (MENUS_FILE,
903 inkscape->menus,
904 menus_skeleton,
905 MENUS_SKELETON_SIZE,
906 _("%s is not a regular file.\n%s"),
907 _("%s not a valid XML file, or\n"
908 "you don't have read permissions on it.\n%s"),
909 _("%s is not a valid menus file.\n%s"),
910 _("Inkscape will run with default menus.\n"
911 "New menus will not be saved."));
912 } else {
913 INKSCAPE->menus = sp_repr_read_mem(menus_skeleton, MENUS_SKELETON_SIZE, NULL);
914 if (INKSCAPE->menus != NULL)
915 retval = true;
916 }
917 g_free(fn);
918 return retval;
919 }
921 /**
922 * We use '.' as separator
923 * \param inkscape Unused
924 */
925 Inkscape::XML::Node *
926 inkscape_get_repr (Inkscape::Application *inkscape, const gchar *key)
927 {
928 if ( (key == NULL) || (inkscape == NULL) ) {
929 return NULL;
930 }
932 Inkscape::XML::Node *prefs = Inkscape::Preferences::get();
933 if ( !prefs ) {
934 return NULL;
935 }
937 Inkscape::XML::Node *repr = prefs->root();
938 if (!repr) return NULL;
939 g_assert (!(strcmp (repr->name(), "inkscape")));
941 gchar const *s = key;
942 while ((s) && (*s)) {
944 /* Find next name */
945 gchar const *e = strchr (s, '.');
946 guint len;
947 if (e) {
948 len = e++ - s;
949 } else {
950 len = strlen (s);
951 }
953 Inkscape::XML::Node* child;
954 for (child = repr->firstChild(); child != NULL; child = child->next()) {
955 gchar const *id = child->attribute("id");
956 if ((id) && (strlen (id) == len) && (!strncmp (id, s, len)))
957 {
958 break;
959 }
960 }
961 if (child == NULL) {
962 return NULL;
963 }
965 repr = child;
966 s = e;
967 }
968 return repr;
969 }
973 void
974 inkscape_selection_modified (Inkscape::Selection *selection, guint flags)
975 {
976 if (Inkscape::NSApplication::Application::getNewGui()) {
977 Inkscape::NSApplication::Editor::selectionModified (selection, flags);
978 return;
979 }
980 g_return_if_fail (selection != NULL);
982 if (DESKTOP_IS_ACTIVE (selection->desktop())) {
983 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[MODIFY_SELECTION], 0, selection, flags);
984 }
985 }
988 void
989 inkscape_selection_changed (Inkscape::Selection * selection)
990 {
991 if (Inkscape::NSApplication::Application::getNewGui()) {
992 Inkscape::NSApplication::Editor::selectionChanged (selection);
993 return;
994 }
995 g_return_if_fail (selection != NULL);
997 if (DESKTOP_IS_ACTIVE (selection->desktop())) {
998 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, selection);
999 }
1000 }
1002 void
1003 inkscape_subselection_changed (SPDesktop *desktop)
1004 {
1005 if (Inkscape::NSApplication::Application::getNewGui()) {
1006 Inkscape::NSApplication::Editor::subSelectionChanged (desktop);
1007 return;
1008 }
1009 g_return_if_fail (desktop != NULL);
1011 if (DESKTOP_IS_ACTIVE (desktop)) {
1012 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SUBSELECTION], 0, desktop);
1013 }
1014 }
1017 void
1018 inkscape_selection_set (Inkscape::Selection * selection)
1019 {
1020 if (Inkscape::NSApplication::Application::getNewGui()) {
1021 Inkscape::NSApplication::Editor::selectionSet (selection);
1022 return;
1023 }
1024 g_return_if_fail (selection != NULL);
1026 if (DESKTOP_IS_ACTIVE (selection->desktop())) {
1027 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, selection);
1028 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, selection);
1029 }
1030 }
1033 void
1034 inkscape_eventcontext_set (SPEventContext * eventcontext)
1035 {
1036 if (Inkscape::NSApplication::Application::getNewGui()) {
1037 Inkscape::NSApplication::Editor::eventContextSet (eventcontext);
1038 return;
1039 }
1040 g_return_if_fail (eventcontext != NULL);
1041 g_return_if_fail (SP_IS_EVENT_CONTEXT (eventcontext));
1043 if (DESKTOP_IS_ACTIVE (eventcontext->desktop)) {
1044 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, eventcontext);
1045 }
1046 }
1049 void
1050 inkscape_add_desktop (SPDesktop * desktop)
1051 {
1052 g_return_if_fail (desktop != NULL);
1054 if (Inkscape::NSApplication::Application::getNewGui())
1055 {
1056 Inkscape::NSApplication::Editor::addDesktop (desktop);
1057 return;
1058 }
1059 g_return_if_fail (inkscape != NULL);
1061 g_assert (!g_slist_find (inkscape->desktops, desktop));
1063 inkscape->desktops = g_slist_prepend (inkscape->desktops, desktop);
1065 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, desktop);
1066 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, sp_desktop_event_context (desktop));
1067 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, sp_desktop_selection (desktop));
1068 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, sp_desktop_selection (desktop));
1069 }
1073 void
1074 inkscape_remove_desktop (SPDesktop * desktop)
1075 {
1076 g_return_if_fail (desktop != NULL);
1077 if (Inkscape::NSApplication::Application::getNewGui())
1078 {
1079 Inkscape::NSApplication::Editor::removeDesktop (desktop);
1080 return;
1081 }
1082 g_return_if_fail (inkscape != NULL);
1084 g_assert (g_slist_find (inkscape->desktops, desktop));
1086 if (DESKTOP_IS_ACTIVE (desktop)) {
1087 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DEACTIVATE_DESKTOP], 0, desktop);
1088 if (inkscape->desktops->next != NULL) {
1089 SPDesktop * new_desktop = (SPDesktop *) inkscape->desktops->next->data;
1090 inkscape->desktops = g_slist_remove (inkscape->desktops, new_desktop);
1091 inkscape->desktops = g_slist_prepend (inkscape->desktops, new_desktop);
1092 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, new_desktop);
1093 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, sp_desktop_event_context (new_desktop));
1094 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, sp_desktop_selection (new_desktop));
1095 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, sp_desktop_selection (new_desktop));
1096 } else {
1097 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, NULL);
1098 if (sp_desktop_selection(desktop))
1099 sp_desktop_selection(desktop)->clear();
1100 }
1101 }
1103 inkscape->desktops = g_slist_remove (inkscape->desktops, desktop);
1105 // if this was the last desktop, shut down the program
1106 if (inkscape->desktops == NULL) {
1107 inkscape_exit (inkscape);
1108 }
1109 }
1113 void
1114 inkscape_activate_desktop (SPDesktop * desktop)
1115 {
1116 g_return_if_fail (desktop != NULL);
1117 if (Inkscape::NSApplication::Application::getNewGui())
1118 {
1119 Inkscape::NSApplication::Editor::activateDesktop (desktop);
1120 return;
1121 }
1122 g_return_if_fail (inkscape != NULL);
1124 if (DESKTOP_IS_ACTIVE (desktop)) {
1125 return;
1126 }
1128 g_assert (g_slist_find (inkscape->desktops, desktop));
1130 SPDesktop *current = (SPDesktop *) inkscape->desktops->data;
1132 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DEACTIVATE_DESKTOP], 0, current);
1134 inkscape->desktops = g_slist_remove (inkscape->desktops, desktop);
1135 inkscape->desktops = g_slist_prepend (inkscape->desktops, desktop);
1137 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, desktop);
1138 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, sp_desktop_event_context (desktop));
1139 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, sp_desktop_selection (desktop));
1140 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, sp_desktop_selection (desktop));
1141 }
1144 /**
1145 * Resends ACTIVATE_DESKTOP for current desktop; needed when a new desktop has got its window that dialogs will transientize to
1146 */
1147 void
1148 inkscape_reactivate_desktop (SPDesktop * desktop)
1149 {
1150 g_return_if_fail (desktop != NULL);
1151 if (Inkscape::NSApplication::Application::getNewGui())
1152 {
1153 Inkscape::NSApplication::Editor::reactivateDesktop (desktop);
1154 return;
1155 }
1156 g_return_if_fail (inkscape != NULL);
1158 if (DESKTOP_IS_ACTIVE (desktop))
1159 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, desktop);
1160 }
1164 SPDesktop *
1165 inkscape_find_desktop_by_dkey (unsigned int dkey)
1166 {
1167 for (GSList *r = inkscape->desktops; r; r = r->next) {
1168 if (((SPDesktop *) r->data)->dkey == dkey)
1169 return ((SPDesktop *) r->data);
1170 }
1171 return NULL;
1172 }
1177 unsigned int
1178 inkscape_maximum_dkey()
1179 {
1180 unsigned int dkey = 0;
1182 for (GSList *r = inkscape->desktops; r; r = r->next) {
1183 if (((SPDesktop *) r->data)->dkey > dkey)
1184 dkey = ((SPDesktop *) r->data)->dkey;
1185 }
1187 return dkey;
1188 }
1192 SPDesktop *
1193 inkscape_next_desktop ()
1194 {
1195 SPDesktop *d = NULL;
1196 unsigned int dkey_current = ((SPDesktop *) inkscape->desktops->data)->dkey;
1198 if (dkey_current < inkscape_maximum_dkey()) {
1199 // find next existing
1200 for (unsigned int i = dkey_current + 1; i <= inkscape_maximum_dkey(); i++) {
1201 d = inkscape_find_desktop_by_dkey (i);
1202 if (d) {
1203 break;
1204 }
1205 }
1206 } else {
1207 // find first existing
1208 for (unsigned int i = 0; i <= inkscape_maximum_dkey(); i++) {
1209 d = inkscape_find_desktop_by_dkey (i);
1210 if (d) {
1211 break;
1212 }
1213 }
1214 }
1216 g_assert (d);
1218 return d;
1219 }
1223 SPDesktop *
1224 inkscape_prev_desktop ()
1225 {
1226 SPDesktop *d = NULL;
1227 unsigned int dkey_current = ((SPDesktop *) inkscape->desktops->data)->dkey;
1229 if (dkey_current > 0) {
1230 // find prev existing
1231 for (signed int i = dkey_current - 1; i >= 0; i--) {
1232 d = inkscape_find_desktop_by_dkey (i);
1233 if (d) {
1234 break;
1235 }
1236 }
1237 }
1238 if (!d) {
1239 // find last existing
1240 d = inkscape_find_desktop_by_dkey (inkscape_maximum_dkey());
1241 }
1243 g_assert (d);
1245 return d;
1246 }
1250 void
1251 inkscape_switch_desktops_next ()
1252 {
1253 inkscape_next_desktop()->presentWindow();
1254 }
1258 void
1259 inkscape_switch_desktops_prev ()
1260 {
1261 inkscape_prev_desktop()->presentWindow();
1262 }
1266 void
1267 inkscape_dialogs_hide ()
1268 {
1269 if (Inkscape::NSApplication::Application::getNewGui())
1270 Inkscape::NSApplication::Editor::hideDialogs();
1271 else
1272 {
1273 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DIALOGS_HIDE], 0);
1274 inkscape->dialogs_toggle = FALSE;
1275 }
1276 }
1280 void
1281 inkscape_dialogs_unhide ()
1282 {
1283 if (Inkscape::NSApplication::Application::getNewGui())
1284 Inkscape::NSApplication::Editor::unhideDialogs();
1285 else
1286 {
1287 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DIALOGS_UNHIDE], 0);
1288 inkscape->dialogs_toggle = TRUE;
1289 }
1290 }
1294 void
1295 inkscape_dialogs_toggle ()
1296 {
1297 if (inkscape->dialogs_toggle) {
1298 inkscape_dialogs_hide ();
1299 } else {
1300 inkscape_dialogs_unhide ();
1301 }
1302 }
1304 void
1305 inkscape_external_change ()
1306 {
1307 g_return_if_fail (inkscape != NULL);
1309 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[EXTERNAL_CHANGE], 0);
1310 }
1312 /**
1313 * fixme: These need probably signals too
1314 */
1315 void
1316 inkscape_add_document (SPDocument *document)
1317 {
1318 g_return_if_fail (document != NULL);
1320 if (!Inkscape::NSApplication::Application::getNewGui())
1321 {
1322 if ( inkscape->document_set.find(document) == inkscape->document_set.end() ) {
1324 inkscape->documents = g_slist_append (inkscape->documents, document);
1325 }
1326 inkscape->document_set.insert(document);
1327 }
1328 else
1329 {
1330 Inkscape::NSApplication::Editor::addDocument (document);
1331 }
1332 }
1336 void
1337 inkscape_remove_document (SPDocument *document)
1338 {
1339 g_return_if_fail (document != NULL);
1341 if (!Inkscape::NSApplication::Application::getNewGui())
1342 {
1343 inkscape->document_set.erase(document);
1344 if ( inkscape->document_set.find(document) != inkscape->document_set.end() ) {
1345 inkscape->documents = g_slist_remove (inkscape->documents, document);
1346 }
1347 }
1348 else
1349 {
1350 Inkscape::NSApplication::Editor::removeDocument (document);
1351 }
1353 return;
1354 }
1356 SPDesktop *
1357 inkscape_active_desktop (void)
1358 {
1359 if (Inkscape::NSApplication::Application::getNewGui())
1360 return Inkscape::NSApplication::Editor::getActiveDesktop();
1362 if (inkscape->desktops == NULL) {
1363 return NULL;
1364 }
1366 return (SPDesktop *) inkscape->desktops->data;
1367 }
1369 SPDocument *
1370 inkscape_active_document (void)
1371 {
1372 if (Inkscape::NSApplication::Application::getNewGui())
1373 return Inkscape::NSApplication::Editor::getActiveDocument();
1375 if (SP_ACTIVE_DESKTOP) {
1376 return sp_desktop_document (SP_ACTIVE_DESKTOP);
1377 }
1379 return NULL;
1380 }
1382 bool inkscape_is_sole_desktop_for_document(SPDesktop const &desktop) {
1383 SPDocument const* document = desktop.doc();
1384 if (!document) {
1385 return false;
1386 }
1387 for ( GSList *iter = inkscape->desktops ; iter ; iter = iter->next ) {
1388 SPDesktop *other_desktop=(SPDesktop *)iter->data;
1389 SPDocument *other_document=other_desktop->doc();
1390 if ( other_document == document && other_desktop != &desktop ) {
1391 return false;
1392 }
1393 }
1394 return true;
1395 }
1397 SPEventContext *
1398 inkscape_active_event_context (void)
1399 {
1400 if (SP_ACTIVE_DESKTOP) {
1401 return sp_desktop_event_context (SP_ACTIVE_DESKTOP);
1402 }
1404 return NULL;
1405 }
1409 /*#####################
1410 # HELPERS
1411 #####################*/
1413 static bool
1414 inkscape_init_config (Inkscape::XML::Document */*doc*/, const gchar *config_name, const gchar *skeleton,
1415 unsigned int skel_size,
1416 const gchar *e_mkdir,
1417 const gchar *e_notdir,
1418 const gchar *e_ccf,
1419 const gchar *e_cwf,
1420 const gchar *warn)
1421 {
1422 gchar *dn = profile_path(NULL);
1423 bool use_gui = (Inkscape::NSApplication::Application::getNewGui())? Inkscape::NSApplication::Application::getUseGui() : inkscape->use_gui;
1424 if (!Inkscape::IO::file_test(dn, G_FILE_TEST_EXISTS)) {
1425 if (Inkscape::IO::mkdir_utf8name(dn))
1426 {
1427 if (use_gui) {
1428 // Cannot create directory
1429 gchar *safeDn = Inkscape::IO::sanitizeString(dn);
1430 GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_mkdir, safeDn, warn);
1431 gtk_dialog_run (GTK_DIALOG (w));
1432 gtk_widget_destroy (w);
1433 g_free(safeDn);
1434 g_free (dn);
1435 return false;
1436 } else {
1437 g_warning(e_mkdir, dn, warn);
1438 g_free (dn);
1439 return false;
1440 }
1441 }
1443 // Also create (empty for now) subdirectories for the user's stuff
1444 {
1445 gchar *temp_dn = profile_path("templates");
1446 Inkscape::IO::mkdir_utf8name(temp_dn);
1447 }
1448 {
1449 gchar *temp_dn = profile_path("keys");
1450 Inkscape::IO::mkdir_utf8name(temp_dn);
1451 }
1452 {
1453 gchar *temp_dn = profile_path("icons");
1454 Inkscape::IO::mkdir_utf8name(temp_dn);
1455 }
1456 {
1457 gchar *temp_dn = profile_path("extensions");
1458 Inkscape::IO::mkdir_utf8name(temp_dn);
1459 }
1460 {
1461 gchar *temp_dn = profile_path("palettes");
1462 Inkscape::IO::mkdir_utf8name(temp_dn);
1463 }
1465 } else if (!Inkscape::IO::file_test(dn, G_FILE_TEST_IS_DIR)) {
1466 if (use_gui) {
1467 // Not a directory
1468 gchar *safeDn = Inkscape::IO::sanitizeString(dn);
1469 GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_notdir, safeDn, warn);
1470 gtk_dialog_run (GTK_DIALOG (w));
1471 gtk_widget_destroy (w);
1472 g_free( safeDn );
1473 g_free (dn);
1474 return false;
1475 } else {
1476 g_warning(e_notdir, dn, warn);
1477 g_free(dn);
1478 return false;
1479 }
1480 }
1481 g_free (dn);
1483 gchar *fn = profile_path(config_name);
1485 Inkscape::IO::dump_fopen_call(fn, "H");
1486 FILE *fh = Inkscape::IO::fopen_utf8name(fn, "w");
1487 if (!fh) {
1488 if (use_gui) {
1489 /* Cannot create file */
1490 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
1491 GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_ccf, safeFn, warn);
1492 gtk_dialog_run (GTK_DIALOG (w));
1493 gtk_widget_destroy (w);
1494 g_free(safeFn);
1495 g_free (fn);
1496 return false;
1497 } else {
1498 g_warning(e_ccf, fn, warn);
1499 g_free(fn);
1500 return false;
1501 }
1502 }
1503 if ( fwrite(skeleton, 1, skel_size, fh) != skel_size ) {
1504 if (use_gui) {
1505 /* Cannot create file */
1506 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
1507 GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_cwf, safeFn, warn);
1508 gtk_dialog_run (GTK_DIALOG (w));
1509 gtk_widget_destroy (w);
1510 g_free(safeFn);
1511 g_free (fn);
1512 fclose(fh);
1513 return false;
1514 } else {
1515 g_warning(e_cwf, fn, warn);
1516 g_free(fn);
1517 fclose(fh);
1518 return false;
1519 }
1520 }
1522 g_free(fn);
1523 fclose(fh);
1524 return true;
1525 }
1527 void
1528 inkscape_refresh_display (Inkscape::Application *inkscape)
1529 {
1530 for (GSList *l = inkscape->desktops; l != NULL; l = l->next) {
1531 (static_cast<Inkscape::UI::View::View*>(l->data))->requestRedraw();
1532 }
1533 }
1536 /**
1537 * Handler for Inkscape's Exit verb. This emits the shutdown signal,
1538 * saves the preferences if appropriate, and quits.
1539 */
1540 void
1541 inkscape_exit (Inkscape::Application */*inkscape*/)
1542 {
1543 g_assert (INKSCAPE);
1545 //emit shutdown signal so that dialogs could remember layout
1546 g_signal_emit (G_OBJECT (INKSCAPE), inkscape_signals[SHUTDOWN_SIGNAL], 0);
1548 Inkscape::Preferences::save();
1549 gtk_main_quit ();
1550 }
1552 gchar *
1553 homedir_path(const char *filename)
1554 {
1555 static const gchar *homedir = NULL;
1556 if (!homedir) {
1557 homedir = g_get_home_dir();
1558 gchar* utf8Path = g_filename_to_utf8( homedir, -1, NULL, NULL, NULL );
1559 if ( utf8Path )
1560 {
1561 homedir = utf8Path;
1562 if (!g_utf8_validate(homedir, -1, NULL)) {
1563 g_warning( "g_get_home_dir() post A IS NOT UTF-8" );
1564 }
1565 }
1566 }
1567 if (!homedir) {
1568 gchar * path = g_path_get_dirname(INKSCAPE->argv0);
1569 gchar* utf8Path = g_filename_to_utf8( path, -1, NULL, NULL, NULL );
1570 g_free(path);
1571 if ( utf8Path )
1572 {
1573 homedir = utf8Path;
1574 if (!g_utf8_validate(homedir, -1, NULL)) {
1575 g_warning( "g_get_home_dir() post B IS NOT UTF-8" );
1576 }
1577 }
1578 }
1579 return g_build_filename(homedir, filename, NULL);
1580 }
1583 /**
1584 * Get, or guess, or decide the location where the preferences.xml
1585 * file should be located.
1586 */
1587 gchar *
1588 profile_path(const char *filename)
1589 {
1590 static const gchar *prefdir = NULL;
1591 if (!prefdir) {
1592 #ifdef HAS_SHGetSpecialFolderLocation
1593 // prefer c:\Documents and Settings\UserName\Application Data\ to
1594 // c:\Documents and Settings\userName\;
1595 if (!prefdir) {
1596 ITEMIDLIST *pidl = 0;
1597 if ( SHGetSpecialFolderLocation( NULL, CSIDL_APPDATA, &pidl ) == NOERROR ) {
1598 gchar * utf8Path = NULL;
1600 if ( PrintWin32::is_os_wide() ) {
1601 wchar_t pathBuf[MAX_PATH+1];
1602 g_assert(sizeof(wchar_t) == sizeof(gunichar2));
1604 if ( SHGetPathFromIDListW( pidl, pathBuf ) ) {
1605 utf8Path = g_utf16_to_utf8( (gunichar2*)(&pathBuf[0]), -1, NULL, NULL, NULL );
1606 }
1607 } else {
1608 char pathBuf[MAX_PATH+1];
1610 if ( SHGetPathFromIDListA( pidl, pathBuf ) ) {
1611 utf8Path = g_filename_to_utf8( pathBuf, -1, NULL, NULL, NULL );
1612 }
1613 }
1615 if ( utf8Path ) {
1616 if (!g_utf8_validate(utf8Path, -1, NULL)) {
1617 g_warning( "SHGetPathFromIDList%c() resulted in invalid UTF-8", (PrintWin32::is_os_wide() ? 'W' : 'A') );
1618 g_free( utf8Path );
1619 utf8Path = 0;
1620 } else {
1621 prefdir = utf8Path;
1622 }
1623 }
1626 /* not compiling yet...
1628 // Remember to free the list pointer
1629 IMalloc * imalloc = 0;
1630 if ( SHGetMalloc(&imalloc) == NOERROR) {
1631 imalloc->lpVtbl->Free( imalloc, pidl );
1632 imalloc->lpVtbl->Release( imalloc );
1633 }
1634 */
1635 }
1636 }
1637 #endif
1638 if (!prefdir) {
1639 prefdir = homedir_path(NULL);
1640 }
1641 }
1642 return g_build_filename(prefdir, INKSCAPE_PROFILE_DIR, filename, NULL);
1643 }
1645 Inkscape::XML::Node *
1646 inkscape_get_menus (Inkscape::Application * inkscape)
1647 {
1648 Inkscape::XML::Node *repr = inkscape->menus->root();
1649 g_assert (!(strcmp (repr->name(), "inkscape")));
1650 return repr->firstChild();
1651 }
1653 void
1654 inkscape_get_all_desktops(std::list< SPDesktop* >& listbuf)
1655 {
1656 for(GSList* l = inkscape->desktops; l != NULL; l = l->next) {
1657 listbuf.push_back(static_cast< SPDesktop* >(l->data));
1658 }
1659 }
1663 /*
1664 Local Variables:
1665 mode:c++
1666 c-file-style:"stroustrup"
1667 c-file-offsets:((innamespace . 0)(inline-open . 0))
1668 indent-tabs-mode:nil
1669 fill-column:99
1670 End:
1671 */
1672 // vim: expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :