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 autosave_timeout_id = g_timeout_add_seconds(timeout, inkscape_autosave, NULL);
454 }
455 }
458 static void
459 inkscape_init (SPObject * object)
460 {
461 if (!inkscape) {
462 inkscape = (Inkscape::Application *) object;
463 } else {
464 g_assert_not_reached ();
465 }
467 new (&inkscape->document_set) std::multiset<SPDocument *>();
469 inkscape->menus = sp_repr_read_mem (_(menus_skeleton), MENUS_SKELETON_SIZE, NULL);
471 inkscape->documents = NULL;
472 inkscape->desktops = NULL;
474 inkscape->dialogs_toggle = TRUE;
476 inkscape->mapalt=GDK_MOD1_MASK;
477 }
479 static void
480 inkscape_dispose (GObject *object)
481 {
482 Inkscape::Application *inkscape = (Inkscape::Application *) object;
484 while (inkscape->documents) {
485 // we don't otherwise unref, so why here?
486 sp_document_unref((SPDocument *)inkscape->documents->data);
487 }
489 g_assert (!inkscape->desktops);
491 Inkscape::Preferences::save();
493 if (inkscape->menus) {
494 /* fixme: This is not the best place */
495 Inkscape::GC::release(inkscape->menus);
496 inkscape->menus = NULL;
497 }
499 inkscape->document_set.~multiset();
501 G_OBJECT_CLASS (parent_class)->dispose (object);
503 gtk_main_quit ();
504 }
507 void
508 inkscape_ref (void)
509 {
510 if (inkscape)
511 g_object_ref (G_OBJECT (inkscape));
512 }
515 void
516 inkscape_unref (void)
517 {
518 if (inkscape)
519 g_object_unref (G_OBJECT (inkscape));
520 }
522 /* returns the mask of the keyboard modifier to map to Alt, zero if no mapping */
523 /* Needs to be a guint because gdktypes.h does not define a 'no-modifier' value */
524 guint
525 inkscape_mapalt() {
526 return inkscape->mapalt;
527 }
529 /* Sets the keyboard modifer to map to Alt. Zero switches off mapping, as does '1', which is the default */
530 void inkscape_mapalt(guint maskvalue)
531 {
532 if(maskvalue<2 || maskvalue> 5 ){ /* MOD5 is the highest defined in gdktypes.h */
533 inkscape->mapalt=0;
534 }else{
535 inkscape->mapalt=(GDK_MOD1_MASK << (maskvalue-1));
536 }
537 }
539 static void
540 inkscape_activate_desktop_private (Inkscape::Application */*inkscape*/, SPDesktop *desktop)
541 {
542 desktop->set_active (true);
543 }
546 static void
547 inkscape_deactivate_desktop_private (Inkscape::Application */*inkscape*/, SPDesktop *desktop)
548 {
549 desktop->set_active (false);
550 }
553 /* fixme: This is EVIL, and belongs to main after all */
555 #define SP_INDENT 8
558 static void
559 inkscape_crash_handler (int /*signum*/)
560 {
561 using Inkscape::Debug::SimpleEvent;
562 using Inkscape::Debug::EventTracker;
563 using Inkscape::Debug::Logger;
565 static gint recursion = FALSE;
567 /*
568 * reset all signal handlers: any further crashes should just be allowed
569 * to crash normally.
570 * */
571 signal (SIGSEGV, segv_handler );
572 signal (SIGABRT, abrt_handler );
573 signal (SIGFPE, fpe_handler );
574 signal (SIGILL, ill_handler );
575 #ifndef WIN32
576 signal (SIGBUS, bus_handler );
577 #endif
579 /* Stop bizarre loops */
580 if (recursion) {
581 abort ();
582 }
583 recursion = TRUE;
585 EventTracker<SimpleEvent<Inkscape::Debug::Event::CORE> > tracker("crash");
586 tracker.set<SimpleEvent<> >("emergency-save");
588 fprintf(stderr, "\nEmergency save activated!\n");
590 time_t sptime = time (NULL);
591 struct tm *sptm = localtime (&sptime);
592 gchar sptstr[256];
593 strftime (sptstr, 256, "%Y_%m_%d_%H_%M_%S", sptm);
595 gint count = 0;
596 GSList *savednames = NULL;
597 GSList *failednames = NULL;
598 for (GSList *l = inkscape->documents; l != NULL; l = l->next) {
599 SPDocument *doc;
600 Inkscape::XML::Node *repr;
601 doc = (SPDocument *) l->data;
602 repr = sp_document_repr_root (doc);
603 if (doc->isModifiedSinceSave()) {
604 const gchar *docname, *d0, *d;
605 gchar n[64], c[1024];
606 FILE *file;
608 /* originally, the document name was retrieved from
609 * the sodipod:docname attribute */
610 docname = doc->name;
611 if (docname) {
612 /* fixme: Quick hack to remove emergency file suffix */
613 d0 = strrchr ((char*)docname, '.');
614 if (d0 && (d0 > docname)) {
615 d0 = strrchr ((char*)(d0 - 1), '.');
616 if (d0 && (d0 > docname)) {
617 d = d0;
618 while (isdigit (*d) || (*d == '.') || (*d == '_')) d += 1;
619 if (*d) {
620 memcpy (n, docname, MIN (d0 - docname - 1, 64));
621 n[63] = '\0';
622 docname = n;
623 }
624 }
625 }
626 }
628 if (!docname || !*docname) docname = "emergency";
629 // try saving to the profile location
630 g_snprintf (c, 1024, "%.256s.%s.%d", docname, sptstr, count);
631 gchar * location = homedir_path(c);
632 Inkscape::IO::dump_fopen_call(location, "E");
633 file = Inkscape::IO::fopen_utf8name(location, "w");
634 g_free(location);
635 if (!file) {
636 // try saving to /tmp
637 g_snprintf (c, 1024, "/tmp/inkscape-%.256s.%s.%d", docname, sptstr, count);
638 Inkscape::IO::dump_fopen_call(c, "G");
639 file = Inkscape::IO::fopen_utf8name(c, "w");
640 }
641 if (!file) {
642 // try saving to the current directory
643 g_snprintf (c, 1024, "inkscape-%.256s.%s.%d", docname, sptstr, count);
644 Inkscape::IO::dump_fopen_call(c, "F");
645 file = Inkscape::IO::fopen_utf8name(c, "w");
646 }
647 if (file) {
648 sp_repr_save_stream (repr->document(), file, SP_SVG_NS_URI);
649 savednames = g_slist_prepend (savednames, g_strdup (c));
650 fclose (file);
651 } else {
652 docname = repr->attribute("sodipodi:docname");
653 failednames = g_slist_prepend (failednames, (docname) ? g_strdup (docname) : g_strdup (_("Untitled document")));
654 }
655 count++;
656 }
657 }
659 savednames = g_slist_reverse (savednames);
660 failednames = g_slist_reverse (failednames);
661 if (savednames) {
662 fprintf (stderr, "\nEmergency save document locations:\n");
663 for (GSList *l = savednames; l != NULL; l = l->next) {
664 fprintf (stderr, " %s\n", (gchar *) l->data);
665 }
666 }
667 if (failednames) {
668 fprintf (stderr, "\nFailed to do emergency save for documents:\n");
669 for (GSList *l = failednames; l != NULL; l = l->next) {
670 fprintf (stderr, " %s\n", (gchar *) l->data);
671 }
672 }
674 Inkscape::Preferences::save();
676 fprintf (stderr, "Emergency save completed. Inkscape will close now.\n");
677 fprintf (stderr, "If you can reproduce this crash, please file a bug at www.inkscape.org\n");
678 fprintf (stderr, "with a detailed description of the steps leading to the crash, so we can fix it.\n");
680 /* Show nice dialog box */
682 char const *istr = _("Inkscape encountered an internal error and will close now.\n");
683 char const *sstr = _("Automatic backups of unsaved documents were done to the following locations:\n");
684 char const *fstr = _("Automatic backup of the following documents failed:\n");
685 gint nllen = strlen ("\n");
686 gint len = strlen (istr) + strlen (sstr) + strlen (fstr);
687 for (GSList *l = savednames; l != NULL; l = l->next) {
688 len = len + SP_INDENT + strlen ((gchar *) l->data) + nllen;
689 }
690 for (GSList *l = failednames; l != NULL; l = l->next) {
691 len = len + SP_INDENT + strlen ((gchar *) l->data) + nllen;
692 }
693 len += 1;
694 gchar *b = g_new (gchar, len);
695 gint pos = 0;
696 len = strlen (istr);
697 memcpy (b + pos, istr, len);
698 pos += len;
699 if (savednames) {
700 len = strlen (sstr);
701 memcpy (b + pos, sstr, len);
702 pos += len;
703 for (GSList *l = savednames; l != NULL; l = l->next) {
704 memset (b + pos, ' ', SP_INDENT);
705 pos += SP_INDENT;
706 len = strlen ((gchar *) l->data);
707 memcpy (b + pos, l->data, len);
708 pos += len;
709 memcpy (b + pos, "\n", nllen);
710 pos += nllen;
711 }
712 }
713 if (failednames) {
714 len = strlen (fstr);
715 memcpy (b + pos, fstr, len);
716 pos += len;
717 for (GSList *l = failednames; l != NULL; l = l->next) {
718 memset (b + pos, ' ', SP_INDENT);
719 pos += SP_INDENT;
720 len = strlen ((gchar *) l->data);
721 memcpy (b + pos, l->data, len);
722 pos += len;
723 memcpy (b + pos, "\n", nllen);
724 pos += nllen;
725 }
726 }
727 *(b + pos) = '\0';
729 if ( inkscape_get_instance() && inkscape_app_use_gui( inkscape_get_instance() ) ) {
730 GtkWidget *msgbox = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", b);
731 gtk_dialog_run (GTK_DIALOG (msgbox));
732 gtk_widget_destroy (msgbox);
733 }
734 else
735 {
736 g_message( "Error: %s", b );
737 }
738 g_free (b);
740 tracker.clear();
741 Logger::shutdown();
743 /* on exit, allow restored signal handler to take over and crash us */
744 }
748 void
749 inkscape_application_init (const gchar *argv0, gboolean use_gui)
750 {
751 inkscape = (Inkscape::Application *)g_object_new (SP_TYPE_INKSCAPE, NULL);
752 /* fixme: load application defaults */
754 segv_handler = signal (SIGSEGV, inkscape_crash_handler);
755 abrt_handler = signal (SIGABRT, inkscape_crash_handler);
756 fpe_handler = signal (SIGFPE, inkscape_crash_handler);
757 ill_handler = signal (SIGILL, inkscape_crash_handler);
758 #ifndef WIN32
759 bus_handler = signal (SIGBUS, inkscape_crash_handler);
760 #endif
762 inkscape->use_gui = use_gui;
763 inkscape->argv0 = g_strdup(argv0);
765 /* Attempt to load the preferences, and set the save_preferences flag to TRUE
766 if we could, or FALSE if we couldn't */
767 Inkscape::Preferences::load();
768 inkscape_load_menus(inkscape);
770 /* DebugDialog redirection. On Linux, default to OFF, on Win32, default to ON.
771 * Use only if use_gui is enabled
772 */
773 #ifdef WIN32
774 #define DEFAULT_LOG_REDIRECT true
775 #else
776 #define DEFAULT_LOG_REDIRECT false
777 #endif
779 if (use_gui == TRUE && prefs_get_int_attribute("dialogs.debug", "redirect", DEFAULT_LOG_REDIRECT))
780 {
781 Inkscape::UI::Dialogs::DebugDialog::getInstance()->captureLogMessages();
782 }
784 /* Check for global remapping of Alt key */
785 if(use_gui)
786 {
787 inkscape_mapalt(guint(prefs_get_int_attribute("options.mapalt","value",0)));
788 }
790 /* Initialize the extensions */
791 Inkscape::Extension::init();
793 inkscape_autosave_init();
795 return;
796 }
798 /**
799 * Returns the current Inkscape::Application global object
800 */
801 Inkscape::Application *
802 inkscape_get_instance()
803 {
804 return inkscape;
805 }
807 gboolean inkscape_app_use_gui( Inkscape::Application const * app )
808 {
809 return app->use_gui;
810 }
812 /**
813 * Preference management
814 * We use '.' as separator
815 *
816 * Returns TRUE if the config file was successfully loaded, FALSE if not.
817 */
818 bool
819 inkscape_load_config (const gchar *filename, Inkscape::XML::Document *config, const gchar *skeleton,
820 unsigned int skel_size, const gchar *e_notreg, const gchar *e_notxml,
821 const gchar *e_notsp, const gchar *warn)
822 {
823 gchar *fn = profile_path(filename);
824 if (!Inkscape::IO::file_test(fn, G_FILE_TEST_EXISTS)) {
825 bool result;
826 /* No such file */
827 result = inkscape_init_config (config, filename, skeleton,
828 skel_size,
829 _("Cannot create directory %s.\n%s"),
830 _("%s is not a valid directory.\n%s"),
831 _("Cannot create file %s.\n%s"),
832 _("Cannot write file %s.\n%s"),
833 _("Although Inkscape will run, it will use default settings,\n"
834 "and any changes made in preferences will not be saved."));
835 g_free (fn);
836 return result;
837 }
839 if (!Inkscape::IO::file_test(fn, G_FILE_TEST_IS_REGULAR)) {
840 /* Not a regular file */
841 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
842 GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_notreg, safeFn, warn);
843 gtk_dialog_run (GTK_DIALOG (w));
844 gtk_widget_destroy (w);
845 g_free(safeFn);
846 g_free (fn);
847 return false;
848 }
850 Inkscape::XML::Document *doc = sp_repr_read_file (fn, NULL);
851 if (doc == NULL) {
852 /* Not an valid xml file */
853 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
854 GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_notxml, safeFn, warn);
855 gtk_dialog_run (GTK_DIALOG (w));
856 gtk_widget_destroy (w);
857 g_free(safeFn);
858 g_free (fn);
859 return false;
860 }
862 Inkscape::XML::Node *root = doc->root();
863 if (strcmp (root->name(), "inkscape")) {
864 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
865 GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_notsp, safeFn, warn);
866 gtk_dialog_run (GTK_DIALOG (w));
867 gtk_widget_destroy (w);
868 Inkscape::GC::release(doc);
869 g_free(safeFn);
870 g_free (fn);
871 return false;
872 }
874 /** \todo this is a hack, need to figure out how to get
875 * a reasonable merge working with the menus.xml file */
876 if (skel_size == MENUS_SKELETON_SIZE) {
877 if (INKSCAPE)
878 INKSCAPE->menus = doc;
879 doc = config;
880 } else {
881 config->root()->mergeFrom(doc->root(), "id");
882 }
884 Inkscape::GC::release(doc);
885 g_free (fn);
886 return true;
887 }
889 /**
890 * Menus management
891 *
892 */
893 bool
894 inkscape_load_menus (Inkscape::Application *inkscape)
895 {
896 gchar *fn = profile_path(MENUS_FILE);
897 bool retval = false;
898 if (Inkscape::IO::file_test(fn, G_FILE_TEST_EXISTS)) {
899 retval = inkscape_load_config (MENUS_FILE,
900 inkscape->menus,
901 menus_skeleton,
902 MENUS_SKELETON_SIZE,
903 _("%s is not a regular file.\n%s"),
904 _("%s not a valid XML file, or\n"
905 "you don't have read permissions on it.\n%s"),
906 _("%s is not a valid menus file.\n%s"),
907 _("Inkscape will run with default menus.\n"
908 "New menus will not be saved."));
909 } else {
910 INKSCAPE->menus = sp_repr_read_mem(menus_skeleton, MENUS_SKELETON_SIZE, NULL);
911 if (INKSCAPE->menus != NULL)
912 retval = true;
913 }
914 g_free(fn);
915 return retval;
916 }
918 /**
919 * We use '.' as separator
920 * \param inkscape Unused
921 */
922 Inkscape::XML::Node *
923 inkscape_get_repr (Inkscape::Application *inkscape, const gchar *key)
924 {
925 if ( (key == NULL) || (inkscape == NULL) ) {
926 return NULL;
927 }
929 Inkscape::XML::Node *prefs = Inkscape::Preferences::get();
930 if ( !prefs ) {
931 return NULL;
932 }
934 Inkscape::XML::Node *repr = prefs->root();
935 if (!repr) return NULL;
936 g_assert (!(strcmp (repr->name(), "inkscape")));
938 gchar const *s = key;
939 while ((s) && (*s)) {
941 /* Find next name */
942 gchar const *e = strchr (s, '.');
943 guint len;
944 if (e) {
945 len = e++ - s;
946 } else {
947 len = strlen (s);
948 }
950 Inkscape::XML::Node* child;
951 for (child = repr->firstChild(); child != NULL; child = child->next()) {
952 gchar const *id = child->attribute("id");
953 if ((id) && (strlen (id) == len) && (!strncmp (id, s, len)))
954 {
955 break;
956 }
957 }
958 if (child == NULL) {
959 return NULL;
960 }
962 repr = child;
963 s = e;
964 }
965 return repr;
966 }
970 void
971 inkscape_selection_modified (Inkscape::Selection *selection, guint flags)
972 {
973 if (Inkscape::NSApplication::Application::getNewGui()) {
974 Inkscape::NSApplication::Editor::selectionModified (selection, flags);
975 return;
976 }
977 g_return_if_fail (selection != NULL);
979 if (DESKTOP_IS_ACTIVE (selection->desktop())) {
980 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[MODIFY_SELECTION], 0, selection, flags);
981 }
982 }
985 void
986 inkscape_selection_changed (Inkscape::Selection * selection)
987 {
988 if (Inkscape::NSApplication::Application::getNewGui()) {
989 Inkscape::NSApplication::Editor::selectionChanged (selection);
990 return;
991 }
992 g_return_if_fail (selection != NULL);
994 if (DESKTOP_IS_ACTIVE (selection->desktop())) {
995 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, selection);
996 }
997 }
999 void
1000 inkscape_subselection_changed (SPDesktop *desktop)
1001 {
1002 if (Inkscape::NSApplication::Application::getNewGui()) {
1003 Inkscape::NSApplication::Editor::subSelectionChanged (desktop);
1004 return;
1005 }
1006 g_return_if_fail (desktop != NULL);
1008 if (DESKTOP_IS_ACTIVE (desktop)) {
1009 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SUBSELECTION], 0, desktop);
1010 }
1011 }
1014 void
1015 inkscape_selection_set (Inkscape::Selection * selection)
1016 {
1017 if (Inkscape::NSApplication::Application::getNewGui()) {
1018 Inkscape::NSApplication::Editor::selectionSet (selection);
1019 return;
1020 }
1021 g_return_if_fail (selection != NULL);
1023 if (DESKTOP_IS_ACTIVE (selection->desktop())) {
1024 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, selection);
1025 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, selection);
1026 }
1027 }
1030 void
1031 inkscape_eventcontext_set (SPEventContext * eventcontext)
1032 {
1033 if (Inkscape::NSApplication::Application::getNewGui()) {
1034 Inkscape::NSApplication::Editor::eventContextSet (eventcontext);
1035 return;
1036 }
1037 g_return_if_fail (eventcontext != NULL);
1038 g_return_if_fail (SP_IS_EVENT_CONTEXT (eventcontext));
1040 if (DESKTOP_IS_ACTIVE (eventcontext->desktop)) {
1041 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, eventcontext);
1042 }
1043 }
1046 void
1047 inkscape_add_desktop (SPDesktop * desktop)
1048 {
1049 g_return_if_fail (desktop != NULL);
1051 if (Inkscape::NSApplication::Application::getNewGui())
1052 {
1053 Inkscape::NSApplication::Editor::addDesktop (desktop);
1054 return;
1055 }
1056 g_return_if_fail (inkscape != NULL);
1058 g_assert (!g_slist_find (inkscape->desktops, desktop));
1060 inkscape->desktops = g_slist_prepend (inkscape->desktops, desktop);
1062 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, desktop);
1063 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, sp_desktop_event_context (desktop));
1064 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, sp_desktop_selection (desktop));
1065 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, sp_desktop_selection (desktop));
1066 }
1070 void
1071 inkscape_remove_desktop (SPDesktop * desktop)
1072 {
1073 g_return_if_fail (desktop != NULL);
1074 if (Inkscape::NSApplication::Application::getNewGui())
1075 {
1076 Inkscape::NSApplication::Editor::removeDesktop (desktop);
1077 return;
1078 }
1079 g_return_if_fail (inkscape != NULL);
1081 g_assert (g_slist_find (inkscape->desktops, desktop));
1083 if (DESKTOP_IS_ACTIVE (desktop)) {
1084 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DEACTIVATE_DESKTOP], 0, desktop);
1085 if (inkscape->desktops->next != NULL) {
1086 SPDesktop * new_desktop = (SPDesktop *) inkscape->desktops->next->data;
1087 inkscape->desktops = g_slist_remove (inkscape->desktops, new_desktop);
1088 inkscape->desktops = g_slist_prepend (inkscape->desktops, new_desktop);
1089 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, new_desktop);
1090 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, sp_desktop_event_context (new_desktop));
1091 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, sp_desktop_selection (new_desktop));
1092 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, sp_desktop_selection (new_desktop));
1093 } else {
1094 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, NULL);
1095 if (sp_desktop_selection(desktop))
1096 sp_desktop_selection(desktop)->clear();
1097 }
1098 }
1100 inkscape->desktops = g_slist_remove (inkscape->desktops, desktop);
1102 // if this was the last desktop, shut down the program
1103 if (inkscape->desktops == NULL) {
1104 inkscape_exit (inkscape);
1105 }
1106 }
1110 void
1111 inkscape_activate_desktop (SPDesktop * desktop)
1112 {
1113 g_return_if_fail (desktop != NULL);
1114 if (Inkscape::NSApplication::Application::getNewGui())
1115 {
1116 Inkscape::NSApplication::Editor::activateDesktop (desktop);
1117 return;
1118 }
1119 g_return_if_fail (inkscape != NULL);
1121 if (DESKTOP_IS_ACTIVE (desktop)) {
1122 return;
1123 }
1125 g_assert (g_slist_find (inkscape->desktops, desktop));
1127 SPDesktop *current = (SPDesktop *) inkscape->desktops->data;
1129 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DEACTIVATE_DESKTOP], 0, current);
1131 inkscape->desktops = g_slist_remove (inkscape->desktops, desktop);
1132 inkscape->desktops = g_slist_prepend (inkscape->desktops, desktop);
1134 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, desktop);
1135 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, sp_desktop_event_context (desktop));
1136 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, sp_desktop_selection (desktop));
1137 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, sp_desktop_selection (desktop));
1138 }
1141 /**
1142 * Resends ACTIVATE_DESKTOP for current desktop; needed when a new desktop has got its window that dialogs will transientize to
1143 */
1144 void
1145 inkscape_reactivate_desktop (SPDesktop * desktop)
1146 {
1147 g_return_if_fail (desktop != NULL);
1148 if (Inkscape::NSApplication::Application::getNewGui())
1149 {
1150 Inkscape::NSApplication::Editor::reactivateDesktop (desktop);
1151 return;
1152 }
1153 g_return_if_fail (inkscape != NULL);
1155 if (DESKTOP_IS_ACTIVE (desktop))
1156 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, desktop);
1157 }
1161 SPDesktop *
1162 inkscape_find_desktop_by_dkey (unsigned int dkey)
1163 {
1164 for (GSList *r = inkscape->desktops; r; r = r->next) {
1165 if (((SPDesktop *) r->data)->dkey == dkey)
1166 return ((SPDesktop *) r->data);
1167 }
1168 return NULL;
1169 }
1174 unsigned int
1175 inkscape_maximum_dkey()
1176 {
1177 unsigned int dkey = 0;
1179 for (GSList *r = inkscape->desktops; r; r = r->next) {
1180 if (((SPDesktop *) r->data)->dkey > dkey)
1181 dkey = ((SPDesktop *) r->data)->dkey;
1182 }
1184 return dkey;
1185 }
1189 SPDesktop *
1190 inkscape_next_desktop ()
1191 {
1192 SPDesktop *d = NULL;
1193 unsigned int dkey_current = ((SPDesktop *) inkscape->desktops->data)->dkey;
1195 if (dkey_current < inkscape_maximum_dkey()) {
1196 // find next existing
1197 for (unsigned int i = dkey_current + 1; i <= inkscape_maximum_dkey(); i++) {
1198 d = inkscape_find_desktop_by_dkey (i);
1199 if (d) {
1200 break;
1201 }
1202 }
1203 } else {
1204 // find first existing
1205 for (unsigned int i = 0; i <= inkscape_maximum_dkey(); i++) {
1206 d = inkscape_find_desktop_by_dkey (i);
1207 if (d) {
1208 break;
1209 }
1210 }
1211 }
1213 g_assert (d);
1215 return d;
1216 }
1220 SPDesktop *
1221 inkscape_prev_desktop ()
1222 {
1223 SPDesktop *d = NULL;
1224 unsigned int dkey_current = ((SPDesktop *) inkscape->desktops->data)->dkey;
1226 if (dkey_current > 0) {
1227 // find prev existing
1228 for (signed int i = dkey_current - 1; i >= 0; i--) {
1229 d = inkscape_find_desktop_by_dkey (i);
1230 if (d) {
1231 break;
1232 }
1233 }
1234 }
1235 if (!d) {
1236 // find last existing
1237 d = inkscape_find_desktop_by_dkey (inkscape_maximum_dkey());
1238 }
1240 g_assert (d);
1242 return d;
1243 }
1247 void
1248 inkscape_switch_desktops_next ()
1249 {
1250 inkscape_next_desktop()->presentWindow();
1251 }
1255 void
1256 inkscape_switch_desktops_prev ()
1257 {
1258 inkscape_prev_desktop()->presentWindow();
1259 }
1263 void
1264 inkscape_dialogs_hide ()
1265 {
1266 if (Inkscape::NSApplication::Application::getNewGui())
1267 Inkscape::NSApplication::Editor::hideDialogs();
1268 else
1269 {
1270 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DIALOGS_HIDE], 0);
1271 inkscape->dialogs_toggle = FALSE;
1272 }
1273 }
1277 void
1278 inkscape_dialogs_unhide ()
1279 {
1280 if (Inkscape::NSApplication::Application::getNewGui())
1281 Inkscape::NSApplication::Editor::unhideDialogs();
1282 else
1283 {
1284 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[DIALOGS_UNHIDE], 0);
1285 inkscape->dialogs_toggle = TRUE;
1286 }
1287 }
1291 void
1292 inkscape_dialogs_toggle ()
1293 {
1294 if (inkscape->dialogs_toggle) {
1295 inkscape_dialogs_hide ();
1296 } else {
1297 inkscape_dialogs_unhide ();
1298 }
1299 }
1301 void
1302 inkscape_external_change ()
1303 {
1304 g_return_if_fail (inkscape != NULL);
1306 g_signal_emit (G_OBJECT (inkscape), inkscape_signals[EXTERNAL_CHANGE], 0);
1307 }
1309 /**
1310 * fixme: These need probably signals too
1311 */
1312 void
1313 inkscape_add_document (SPDocument *document)
1314 {
1315 g_return_if_fail (document != NULL);
1317 if (!Inkscape::NSApplication::Application::getNewGui())
1318 {
1319 if ( inkscape->document_set.find(document) == inkscape->document_set.end() ) {
1321 inkscape->documents = g_slist_append (inkscape->documents, document);
1322 }
1323 inkscape->document_set.insert(document);
1324 }
1325 else
1326 {
1327 Inkscape::NSApplication::Editor::addDocument (document);
1328 }
1329 }
1333 void
1334 inkscape_remove_document (SPDocument *document)
1335 {
1336 g_return_if_fail (document != NULL);
1338 if (!Inkscape::NSApplication::Application::getNewGui())
1339 {
1340 inkscape->document_set.erase(document);
1341 if ( inkscape->document_set.find(document) != inkscape->document_set.end() ) {
1342 inkscape->documents = g_slist_remove (inkscape->documents, document);
1343 }
1344 }
1345 else
1346 {
1347 Inkscape::NSApplication::Editor::removeDocument (document);
1348 }
1350 return;
1351 }
1353 SPDesktop *
1354 inkscape_active_desktop (void)
1355 {
1356 if (Inkscape::NSApplication::Application::getNewGui())
1357 return Inkscape::NSApplication::Editor::getActiveDesktop();
1359 if (inkscape->desktops == NULL) {
1360 return NULL;
1361 }
1363 return (SPDesktop *) inkscape->desktops->data;
1364 }
1366 SPDocument *
1367 inkscape_active_document (void)
1368 {
1369 if (Inkscape::NSApplication::Application::getNewGui())
1370 return Inkscape::NSApplication::Editor::getActiveDocument();
1372 if (SP_ACTIVE_DESKTOP) {
1373 return sp_desktop_document (SP_ACTIVE_DESKTOP);
1374 }
1376 return NULL;
1377 }
1379 bool inkscape_is_sole_desktop_for_document(SPDesktop const &desktop) {
1380 SPDocument const* document = desktop.doc();
1381 if (!document) {
1382 return false;
1383 }
1384 for ( GSList *iter = inkscape->desktops ; iter ; iter = iter->next ) {
1385 SPDesktop *other_desktop=(SPDesktop *)iter->data;
1386 SPDocument *other_document=other_desktop->doc();
1387 if ( other_document == document && other_desktop != &desktop ) {
1388 return false;
1389 }
1390 }
1391 return true;
1392 }
1394 SPEventContext *
1395 inkscape_active_event_context (void)
1396 {
1397 if (SP_ACTIVE_DESKTOP) {
1398 return sp_desktop_event_context (SP_ACTIVE_DESKTOP);
1399 }
1401 return NULL;
1402 }
1406 /*#####################
1407 # HELPERS
1408 #####################*/
1410 static bool
1411 inkscape_init_config (Inkscape::XML::Document */*doc*/, const gchar *config_name, const gchar *skeleton,
1412 unsigned int skel_size,
1413 const gchar *e_mkdir,
1414 const gchar *e_notdir,
1415 const gchar *e_ccf,
1416 const gchar *e_cwf,
1417 const gchar *warn)
1418 {
1419 gchar *dn = profile_path(NULL);
1420 bool use_gui = (Inkscape::NSApplication::Application::getNewGui())? Inkscape::NSApplication::Application::getUseGui() : inkscape->use_gui;
1421 if (!Inkscape::IO::file_test(dn, G_FILE_TEST_EXISTS)) {
1422 if (Inkscape::IO::mkdir_utf8name(dn))
1423 {
1424 if (use_gui) {
1425 // Cannot create directory
1426 gchar *safeDn = Inkscape::IO::sanitizeString(dn);
1427 GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_mkdir, safeDn, warn);
1428 gtk_dialog_run (GTK_DIALOG (w));
1429 gtk_widget_destroy (w);
1430 g_free(safeDn);
1431 g_free (dn);
1432 return false;
1433 } else {
1434 g_warning(e_mkdir, dn, warn);
1435 g_free (dn);
1436 return false;
1437 }
1438 }
1440 // Also create (empty for now) subdirectories for the user's stuff
1441 {
1442 gchar *temp_dn = profile_path("templates");
1443 Inkscape::IO::mkdir_utf8name(temp_dn);
1444 }
1445 {
1446 gchar *temp_dn = profile_path("keys");
1447 Inkscape::IO::mkdir_utf8name(temp_dn);
1448 }
1449 {
1450 gchar *temp_dn = profile_path("icons");
1451 Inkscape::IO::mkdir_utf8name(temp_dn);
1452 }
1453 {
1454 gchar *temp_dn = profile_path("extensions");
1455 Inkscape::IO::mkdir_utf8name(temp_dn);
1456 }
1457 {
1458 gchar *temp_dn = profile_path("palettes");
1459 Inkscape::IO::mkdir_utf8name(temp_dn);
1460 }
1462 } else if (!Inkscape::IO::file_test(dn, G_FILE_TEST_IS_DIR)) {
1463 if (use_gui) {
1464 // Not a directory
1465 gchar *safeDn = Inkscape::IO::sanitizeString(dn);
1466 GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_notdir, safeDn, warn);
1467 gtk_dialog_run (GTK_DIALOG (w));
1468 gtk_widget_destroy (w);
1469 g_free( safeDn );
1470 g_free (dn);
1471 return false;
1472 } else {
1473 g_warning(e_notdir, dn, warn);
1474 g_free(dn);
1475 return false;
1476 }
1477 }
1478 g_free (dn);
1480 gchar *fn = profile_path(config_name);
1482 Inkscape::IO::dump_fopen_call(fn, "H");
1483 FILE *fh = Inkscape::IO::fopen_utf8name(fn, "w");
1484 if (!fh) {
1485 if (use_gui) {
1486 /* Cannot create file */
1487 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
1488 GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_ccf, safeFn, warn);
1489 gtk_dialog_run (GTK_DIALOG (w));
1490 gtk_widget_destroy (w);
1491 g_free(safeFn);
1492 g_free (fn);
1493 return false;
1494 } else {
1495 g_warning(e_ccf, fn, warn);
1496 g_free(fn);
1497 return false;
1498 }
1499 }
1500 if ( fwrite(skeleton, 1, skel_size, fh) != skel_size ) {
1501 if (use_gui) {
1502 /* Cannot create file */
1503 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
1504 GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, e_cwf, safeFn, warn);
1505 gtk_dialog_run (GTK_DIALOG (w));
1506 gtk_widget_destroy (w);
1507 g_free(safeFn);
1508 g_free (fn);
1509 fclose(fh);
1510 return false;
1511 } else {
1512 g_warning(e_cwf, fn, warn);
1513 g_free(fn);
1514 fclose(fh);
1515 return false;
1516 }
1517 }
1519 g_free(fn);
1520 fclose(fh);
1521 return true;
1522 }
1524 void
1525 inkscape_refresh_display (Inkscape::Application *inkscape)
1526 {
1527 for (GSList *l = inkscape->desktops; l != NULL; l = l->next) {
1528 (static_cast<Inkscape::UI::View::View*>(l->data))->requestRedraw();
1529 }
1530 }
1533 /**
1534 * Handler for Inkscape's Exit verb. This emits the shutdown signal,
1535 * saves the preferences if appropriate, and quits.
1536 */
1537 void
1538 inkscape_exit (Inkscape::Application */*inkscape*/)
1539 {
1540 g_assert (INKSCAPE);
1542 //emit shutdown signal so that dialogs could remember layout
1543 g_signal_emit (G_OBJECT (INKSCAPE), inkscape_signals[SHUTDOWN_SIGNAL], 0);
1545 Inkscape::Preferences::save();
1546 gtk_main_quit ();
1547 }
1549 gchar *
1550 homedir_path(const char *filename)
1551 {
1552 static const gchar *homedir = NULL;
1553 if (!homedir) {
1554 homedir = g_get_home_dir();
1555 gchar* utf8Path = g_filename_to_utf8( homedir, -1, NULL, NULL, NULL );
1556 if ( utf8Path )
1557 {
1558 homedir = utf8Path;
1559 if (!g_utf8_validate(homedir, -1, NULL)) {
1560 g_warning( "g_get_home_dir() post A IS NOT UTF-8" );
1561 }
1562 }
1563 }
1564 if (!homedir) {
1565 gchar * path = g_path_get_dirname(INKSCAPE->argv0);
1566 gchar* utf8Path = g_filename_to_utf8( path, -1, NULL, NULL, NULL );
1567 g_free(path);
1568 if ( utf8Path )
1569 {
1570 homedir = utf8Path;
1571 if (!g_utf8_validate(homedir, -1, NULL)) {
1572 g_warning( "g_get_home_dir() post B IS NOT UTF-8" );
1573 }
1574 }
1575 }
1576 return g_build_filename(homedir, filename, NULL);
1577 }
1580 /**
1581 * Get, or guess, or decide the location where the preferences.xml
1582 * file should be located.
1583 */
1584 gchar *
1585 profile_path(const char *filename)
1586 {
1587 static const gchar *prefdir = NULL;
1588 if (!prefdir) {
1589 #ifdef HAS_SHGetSpecialFolderLocation
1590 // prefer c:\Documents and Settings\UserName\Application Data\ to
1591 // c:\Documents and Settings\userName\;
1592 if (!prefdir) {
1593 ITEMIDLIST *pidl = 0;
1594 if ( SHGetSpecialFolderLocation( NULL, CSIDL_APPDATA, &pidl ) == NOERROR ) {
1595 gchar * utf8Path = NULL;
1597 if ( PrintWin32::is_os_wide() ) {
1598 wchar_t pathBuf[MAX_PATH+1];
1599 g_assert(sizeof(wchar_t) == sizeof(gunichar2));
1601 if ( SHGetPathFromIDListW( pidl, pathBuf ) ) {
1602 utf8Path = g_utf16_to_utf8( (gunichar2*)(&pathBuf[0]), -1, NULL, NULL, NULL );
1603 }
1604 } else {
1605 char pathBuf[MAX_PATH+1];
1607 if ( SHGetPathFromIDListA( pidl, pathBuf ) ) {
1608 utf8Path = g_filename_to_utf8( pathBuf, -1, NULL, NULL, NULL );
1609 }
1610 }
1612 if ( utf8Path ) {
1613 if (!g_utf8_validate(utf8Path, -1, NULL)) {
1614 g_warning( "SHGetPathFromIDList%c() resulted in invalid UTF-8", (PrintWin32::is_os_wide() ? 'W' : 'A') );
1615 g_free( utf8Path );
1616 utf8Path = 0;
1617 } else {
1618 prefdir = utf8Path;
1619 }
1620 }
1623 /* not compiling yet...
1625 // Remember to free the list pointer
1626 IMalloc * imalloc = 0;
1627 if ( SHGetMalloc(&imalloc) == NOERROR) {
1628 imalloc->lpVtbl->Free( imalloc, pidl );
1629 imalloc->lpVtbl->Release( imalloc );
1630 }
1631 */
1632 }
1633 }
1634 #endif
1635 if (!prefdir) {
1636 prefdir = homedir_path(NULL);
1637 }
1638 }
1639 return g_build_filename(prefdir, INKSCAPE_PROFILE_DIR, filename, NULL);
1640 }
1642 Inkscape::XML::Node *
1643 inkscape_get_menus (Inkscape::Application * inkscape)
1644 {
1645 Inkscape::XML::Node *repr = inkscape->menus->root();
1646 g_assert (!(strcmp (repr->name(), "inkscape")));
1647 return repr->firstChild();
1648 }
1650 void
1651 inkscape_get_all_desktops(std::list< SPDesktop* >& listbuf)
1652 {
1653 for(GSList* l = inkscape->desktops; l != NULL; l = l->next) {
1654 listbuf.push_back(static_cast< SPDesktop* >(l->data));
1655 }
1656 }
1660 /*
1661 Local Variables:
1662 mode:c++
1663 c-file-style:"stroustrup"
1664 c-file-offsets:((innamespace . 0)(inline-open . 0))
1665 indent-tabs-mode:nil
1666 fill-column:99
1667 End:
1668 */
1669 // vim: expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :