~centralelyon2010/inkscape/imagelinks2

« back to all changes in this revision

Viewing changes to src/inkscape.cpp

  • Committer: mental
  • Date: 2006-01-16 02:36:01 UTC
  • Revision ID: mental@users.sourceforge.net-20060116023601-wkr0h7edl5veyudq
moving trunk for module inkscape

Show diffs side-by-side

added added

removed removed

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