Code

Objects will now change when their linked colors change.
[inkscape.git] / src / interface.cpp
1 #define __SP_INTERFACE_C__
3 /**
4  * Main UI stuff
5  *
6  * Authors:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *   Frank Felfe <innerspace@iname.com>
9  *   bulia byak <buliabyak@users.sf.net>
10  *
11  * Copyright (C) 1999-2005 authors
12  * Copyright (C) 2001-2002 Ximian, Inc.
13  * Copyright (C) 2004 David Turner
14  *
15  * Released under GNU GPL, read the file 'COPYING' for more information
16  */
18 #ifdef HAVE_CONFIG_H
19 # include "config.h"
20 #endif
22 #include <gtk/gtk.h>
23 #include "inkscape-private.h"
24 #include "extension/effect.h"
25 #include "widgets/icon.h"
26 #include "prefs-utils.h"
27 #include "path-prefix.h"
29 #include "shortcuts.h"
31 #include "document.h"
32 #include "desktop-handles.h"
33 #include "file.h"
34 #include "interface.h"
35 #include "desktop.h"
36 #include "object-ui.h"
37 #include "selection.h"
38 #include "selection-chemistry.h"
39 #include "svg-view-widget.h"
40 #include "widgets/desktop-widget.h"
41 #include "sp-item-group.h"
42 #include "sp-namedview.h"
44 #include "helper/action.h"
45 #include "helper/gnome-utils.h"
46 #include "helper/window.h"
48 #include "io/sys.h"
49 #include "io/stringstream.h"
50 #include "io/base64stream.h"
52 #include "dialogs/dialog-events.h"
54 #include "message-context.h"
56 // Added for color drag-n-drop
57 #include "display/sp-canvas.h"
58 #include "color.h"
59 #include "svg/svg-color.h"
60 #include "desktop-style.h"
61 #include "style.h"
64 using Inkscape::IO::StringOutputStream;
65 using Inkscape::IO::Base64OutputStream;
67 /* forward declaration */
68 static gint sp_ui_delete(GtkWidget *widget, GdkEvent *event, Inkscape::UI::View::View *view);
70 /* Drag and Drop */
71 typedef enum {
72     URI_LIST,
73     SVG_XML_DATA,
74     SVG_DATA,
75     PNG_DATA,
76     JPEG_DATA,
77     IMAGE_DATA,
78     APP_X_INKY_COLOR,
79     APP_X_COLOR
80 } ui_drop_target_info;
82 static GtkTargetEntry ui_drop_target_entries [] = {
83     {"text/uri-list", 0, URI_LIST},
84     {"image/svg+xml", 0, SVG_XML_DATA},
85     {"image/svg",     0, SVG_DATA},
86     {"image/png",     0, PNG_DATA},
87     {"image/jpeg",    0, JPEG_DATA},
88     {"application/x-inkscape-color", 0, APP_X_INKY_COLOR},
89     {"application/x-color", 0, APP_X_COLOR}
90 };
92 static GtkTargetEntry *completeDropTargets = 0;
93 static int completeDropTargetsCount = 0;
95 #define ENTRIES_SIZE(n) sizeof(n)/sizeof(n[0])
96 static guint nui_drop_target_entries = ENTRIES_SIZE(ui_drop_target_entries);
97 static void sp_ui_import_files(gchar *buffer);
98 static void sp_ui_import_one_file(char const *filename);
99 static void sp_ui_import_one_file_with_check(gpointer filename, gpointer unused);
100 static void sp_ui_drag_data_received(GtkWidget *widget,
101                                      GdkDragContext *drag_context,
102                                      gint x, gint y,
103                                      GtkSelectionData *data,
104                                      guint info,
105                                      guint event_time,
106                                      gpointer user_data);
107 static void sp_ui_menu_item_set_sensitive(SPAction *action,
108                                           unsigned int sensitive,
109                                           void *data);
111 SPActionEventVector menu_item_event_vector = {
112     {NULL},
113     NULL,
114     NULL, /* set_active */
115     sp_ui_menu_item_set_sensitive, /* set_sensitive */
116     NULL  /* set_shortcut */
117 };
119 void
120 sp_create_window(SPViewWidget *vw, gboolean editable)
122     GtkWidget *w, *hb;
124     g_return_if_fail(vw != NULL);
125     g_return_if_fail(SP_IS_VIEW_WIDGET(vw));
127     w = sp_window_new("", TRUE);
129     if (editable) {
130       g_object_set_data(G_OBJECT(vw), "window", w);
131       reinterpret_cast<SPDesktopWidget*>(vw)->window =
132         static_cast<GtkWindow*>((void*)w);
133     }
135     hb = gtk_hbox_new(FALSE, 0);
136     gtk_widget_show(hb);
137     gtk_container_add(GTK_CONTAINER(w), hb);
138     g_object_set_data(G_OBJECT(w), "hbox", hb);
140     /* fixme: */
141     if (editable) {
142         gtk_window_set_default_size((GtkWindow *) w, 640, 480);
143         g_object_set_data(G_OBJECT(w), "desktop", SP_DESKTOP_WIDGET(vw)->desktop);
144         g_object_set_data(G_OBJECT(w), "desktopwidget", vw);
145         g_signal_connect(G_OBJECT(w), "delete_event", G_CALLBACK(sp_ui_delete), vw->view);
146         g_signal_connect(G_OBJECT(w), "focus_in_event", G_CALLBACK(sp_desktop_widget_set_focus), vw);
147     } else {
148         gtk_window_set_policy(GTK_WINDOW(w), TRUE, TRUE, TRUE);
149     }
151     gtk_box_pack_end(GTK_BOX(hb), GTK_WIDGET(vw), TRUE, TRUE, 0);
152     gtk_widget_show(GTK_WIDGET(vw));
155     if ( completeDropTargets == 0 || completeDropTargetsCount == 0 )
156     {
157         std::vector<gchar*> types;
159         GSList *list = gdk_pixbuf_get_formats();
160         while ( list ) {
161             int i = 0;
162             GdkPixbufFormat *one = (GdkPixbufFormat*)list->data;
163             gchar** typesXX = gdk_pixbuf_format_get_mime_types(one);
164             for ( i = 0; typesXX[i]; i++ ) {
165                 types.push_back(g_strdup(typesXX[i]));
166             }
167             g_strfreev(typesXX);
169             list = g_slist_next(list);
170         }
171         completeDropTargetsCount = nui_drop_target_entries + types.size();
172         completeDropTargets = new GtkTargetEntry[completeDropTargetsCount];
173         for ( int i = 0; i < (int)nui_drop_target_entries; i++ ) {
174             completeDropTargets[i] = ui_drop_target_entries[i];
175         }
176         int pos = nui_drop_target_entries;
178         for (std::vector<gchar*>::iterator it = types.begin() ; it != types.end() ; it++) {
179             completeDropTargets[pos].target = *it;
180             completeDropTargets[pos].flags = 0;
181             completeDropTargets[pos].info = IMAGE_DATA;
182             pos++;
183         }
184     }
186     gtk_drag_dest_set(w,
187                       GTK_DEST_DEFAULT_ALL,
188                       completeDropTargets,
189                       completeDropTargetsCount,
190                       GdkDragAction(GDK_ACTION_COPY | GDK_ACTION_MOVE));
191     g_signal_connect(G_OBJECT(w),
192                      "drag_data_received",
193                      G_CALLBACK(sp_ui_drag_data_received),
194                      NULL);
195     gtk_widget_show(w);
197     // needed because the first ACTIVATE_DESKTOP was sent when there was no window yet
198     inkscape_reactivate_desktop(SP_DESKTOP_WIDGET(vw)->desktop);
201 void
202 sp_ui_new_view()
204     SPDocument *document;
205     SPViewWidget *dtw;
207     document = SP_ACTIVE_DOCUMENT;
208     if (!document) return;
210     dtw = sp_desktop_widget_new(sp_document_namedview(document, NULL));
211     g_return_if_fail(dtw != NULL);
213     sp_create_window(dtw, TRUE);
214     sp_namedview_window_from_document(static_cast<SPDesktop*>(dtw->view));
217 /* TODO: not yet working */
218 /* To be re-enabled (by adding to menu) once it works. */
219 void
220 sp_ui_new_view_preview()
222     SPDocument *document;
223     SPViewWidget *dtw;
225     document = SP_ACTIVE_DOCUMENT;
226     if (!document) return;
228     dtw = (SPViewWidget *) sp_svg_view_widget_new(document);
229     g_return_if_fail(dtw != NULL);
230     sp_svg_view_widget_set_resize(SP_SVG_VIEW_WIDGET(dtw), TRUE, 400.0, 400.0);
232     sp_create_window(dtw, FALSE);
235 /**
236  * \param widget unused
237  */
238 void
239 sp_ui_close_view(GtkWidget *widget)
241     if (SP_ACTIVE_DESKTOP == NULL) {
242         return;
243     }
244     if ((SP_ACTIVE_DESKTOP)->shutdown()) {
245         return;
246     }
247     SP_ACTIVE_DESKTOP->destroyWidget();
251 /**
252  *  sp_ui_close_all
253  *
254  *  This function is called to exit the program, and iterates through all
255  *  open document view windows, attempting to close each in turn.  If the
256  *  view has unsaved information, the user will be prompted to save,
257  *  discard, or cancel.
258  *
259  *  Returns FALSE if the user cancels the close_all operation, TRUE
260  *  otherwise.
261  */
262 unsigned int
263 sp_ui_close_all(void)
265     /* Iterate through all the windows, destroying each in the order they
266        become active */
267     while (SP_ACTIVE_DESKTOP) {
268         if ((SP_ACTIVE_DESKTOP)->shutdown()) {
269             /* The user cancelled the operation, so end doing the close */
270             return FALSE;
271         }
272         SP_ACTIVE_DESKTOP->destroyWidget();
273     }
275     return TRUE;
278 static gint
279 sp_ui_delete(GtkWidget *widget, GdkEvent *event, Inkscape::UI::View::View *view)
281     return view->shutdown();
284 /*
285  * Some day when the right-click menus are ready to start working
286  * smarter with the verbs, we'll need to change this NULL being
287  * sent to sp_action_perform to something useful, or set some kind
288  * of global "right-clicked position" variable for actions to
289  * investigate when they're called.
290  */
291 static void
292 sp_ui_menu_activate(void *object, SPAction *action)
294     sp_action_perform(action, NULL);
297 static void
298 sp_ui_menu_select_action(void *object, SPAction *action)
300     action->view->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, action->tip);
303 static void
304 sp_ui_menu_deselect_action(void *object, SPAction *action)
306     action->view->tipsMessageContext()->clear();
309 static void
310 sp_ui_menu_select(gpointer object, gpointer tip)
312     Inkscape::UI::View::View *view = static_cast<Inkscape::UI::View::View*> (g_object_get_data(G_OBJECT(object), "view"));
313     view->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, (gchar *)tip);
316 static void
317 sp_ui_menu_deselect(gpointer object)
319     Inkscape::UI::View::View *view = static_cast<Inkscape::UI::View::View*>  (g_object_get_data(G_OBJECT(object), "view"));
320     view->tipsMessageContext()->clear();
323 /**
324  * sp_ui_menuitem_add_icon
325  *
326  * Creates and attaches a scaled icon to the given menu item.
327  *
328  */
329 void
330 sp_ui_menuitem_add_icon( GtkWidget *item, gchar *icon_name )
332     GtkWidget *icon;
334     icon = sp_icon_new( GTK_ICON_SIZE_MENU, icon_name );
335     gtk_widget_show(icon);
336     gtk_image_menu_item_set_image((GtkImageMenuItem *) item, icon);
337 } // end of sp_ui_menu_add_icon
339 /**
340  * sp_ui_menu_append_item
341  *
342  * Appends a UI item with specific info for Inkscape/Sodipodi.
343  *
344  */
345 static GtkWidget *
346 sp_ui_menu_append_item( GtkMenu *menu, gchar const *stock,
347                         gchar const *label, gchar const *tip, Inkscape::UI::View::View *view, GCallback callback,
348                         gpointer data, gboolean with_mnemonic = TRUE )
350     GtkWidget *item;
352     if (stock) {
353         item = gtk_image_menu_item_new_from_stock(stock, NULL);
354     } else if (label) {
355         item = (with_mnemonic)
356             ? gtk_image_menu_item_new_with_mnemonic(label) :
357             gtk_image_menu_item_new_with_label(label);
358     } else {
359         item = gtk_separator_menu_item_new();
360     }
362     gtk_widget_show(item);
364     if (callback) {
365         g_signal_connect(G_OBJECT(item), "activate", callback, data);
366     }
368     if (tip && view) {
369         g_object_set_data(G_OBJECT(item), "view", (gpointer) view);
370         g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), (gpointer) tip );
371         g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), NULL);
372     }
374     gtk_menu_append(GTK_MENU(menu), item);
376     return item;
378 } // end of sp_ui_menu_append_item()
380 /**
381 \brief  a wrapper around gdk_keyval_name producing (when possible) characters, not names
382  */
383 static gchar const *
384 sp_key_name(guint keyval)
386     /* TODO: Compare with the definition of gtk_accel_label_refetch in gtk/gtkaccellabel.c (or
387        simply use GtkAccelLabel as the TODO comment in sp_ui_shortcut_string suggests). */
388     gchar const *n = gdk_keyval_name(gdk_keyval_to_upper(keyval));
390     if      (!strcmp(n, "asciicircum"))  return "^";
391     else if (!strcmp(n, "parenleft"  ))  return "(";
392     else if (!strcmp(n, "parenright" ))  return ")";
393     else if (!strcmp(n, "plus"       ))  return "+";
394     else if (!strcmp(n, "minus"      ))  return "-";
395     else if (!strcmp(n, "asterisk"   ))  return "*";
396     else if (!strcmp(n, "KP_Multiply"))  return "*";
397     else if (!strcmp(n, "Delete"     ))  return "Del";
398     else if (!strcmp(n, "Page_Up"    ))  return "PgUp";
399     else if (!strcmp(n, "Page_Down"  ))  return "PgDn";
400     else if (!strcmp(n, "grave"      ))  return "`";
401     else if (!strcmp(n, "numbersign" ))  return "#";
402     else if (!strcmp(n, "bar" ))  return "|";
403     else if (!strcmp(n, "slash" ))  return "/";
404     else if (!strcmp(n, "exclam" ))  return "!";
405     else return n;
409 /**
410  * \param shortcut A GDK keyval OR'd with SP_SHORTCUT_blah_MASK values.
411  * \param c Points to a buffer at least 256 bytes long.
412  */
413 void
414 sp_ui_shortcut_string(unsigned const shortcut, gchar *const c)
416     /* TODO: This function shouldn't exist.  Our callers should use GtkAccelLabel instead of
417      * a generic GtkLabel containing this string, and should call gtk_widget_add_accelerator.
418      * Will probably need to change sp_shortcut_invoke callers.
419      *
420      * The existing gtk_label_new_with_mnemonic call can be replaced with
421      * g_object_new(GTK_TYPE_ACCEL_LABEL, NULL) followed by
422      * gtk_label_set_text_with_mnemonic(lbl, str).
423      */
424     static GtkAccelLabelClass const &accel_lbl_cls
425         = *(GtkAccelLabelClass const *) g_type_class_peek_static(GTK_TYPE_ACCEL_LABEL);
427     struct { unsigned test; char const *name; } const modifier_tbl[] = {
428         { SP_SHORTCUT_SHIFT_MASK,   accel_lbl_cls.mod_name_shift   },
429         { SP_SHORTCUT_CONTROL_MASK, accel_lbl_cls.mod_name_control },
430         { SP_SHORTCUT_ALT_MASK,     accel_lbl_cls.mod_name_alt     }
431     };
433     gchar *p = c;
434     gchar *end = p + 256;
436     for (unsigned i = 0; i < G_N_ELEMENTS(modifier_tbl); ++i) {
437         if ((shortcut & modifier_tbl[i].test)
438             && (p < end))
439         {
440             p += g_snprintf(p, end - p, "%s%s",
441                             modifier_tbl[i].name,
442                             accel_lbl_cls.mod_separator);
443         }
444     }
445     if (p < end) {
446         p += g_snprintf(p, end - p, "%s", sp_key_name(shortcut & 0xffffff));
447     }
448     end[-1] = '\0';  // snprintf doesn't guarantee to nul-terminate the string.
451 void
452 sp_ui_dialog_title_string(Inkscape::Verb *verb, gchar *c)
454     SPAction     *action;
455     unsigned int shortcut;
456     gchar        *s;
457     gchar        key[256];
458     gchar        *atitle;
460     action = verb->get_action(NULL);
461     if (!action)
462         return;
464     atitle = sp_action_get_title(action);
466     s = g_stpcpy(c, atitle);
468     g_free(atitle);
470     shortcut = sp_shortcut_get_primary(verb);
471     if (shortcut) {
472         s = g_stpcpy(s, " (");
473         sp_ui_shortcut_string(shortcut, key);
474         s = g_stpcpy(s, key);
475         s = g_stpcpy(s, ")");
476     }
480 /**
481  * sp_ui_menu_append_item_from_verb
482  *
483  * Appends a custom menu UI from a verb.
484  *
485  */
487 static GtkWidget *
488 sp_ui_menu_append_item_from_verb(GtkMenu *menu, Inkscape::Verb *verb, Inkscape::UI::View::View *view, bool radio = false, GSList *group = NULL)
490     SPAction *action;
491     GtkWidget *item;
493     if (verb->get_code() == SP_VERB_NONE) {
495         item = gtk_separator_menu_item_new();
497     } else {
498         unsigned int shortcut;
500         action = verb->get_action(view);
502         if (!action) return NULL;
504         shortcut = sp_shortcut_get_primary(verb);
505         if (shortcut) {
506             gchar c[256];
507             sp_ui_shortcut_string(shortcut, c);
508             GtkWidget *const hb = gtk_hbox_new(FALSE, 16);
509             GtkWidget *const name_lbl = gtk_label_new("");
510             gtk_label_set_markup_with_mnemonic(GTK_LABEL(name_lbl), action->name);
511             gtk_misc_set_alignment((GtkMisc *) name_lbl, 0.0, 0.5);
512             gtk_box_pack_start((GtkBox *) hb, name_lbl, TRUE, TRUE, 0);
513             GtkWidget *const accel_lbl = gtk_label_new(c);
514             gtk_misc_set_alignment((GtkMisc *) accel_lbl, 1.0, 0.5);
515             gtk_box_pack_end((GtkBox *) hb, accel_lbl, FALSE, FALSE, 0);
516             gtk_widget_show_all(hb);
517             if (radio) {
518                 item = gtk_radio_menu_item_new (group);
519             } else {
520                 item = gtk_image_menu_item_new();
521             }
522             gtk_container_add((GtkContainer *) item, hb);
523         } else {
524             if (radio) {
525                 item = gtk_radio_menu_item_new (group);
526             } else {
527                 item = gtk_image_menu_item_new ();
528             }
529             GtkWidget *const name_lbl = gtk_label_new("");
530             gtk_label_set_markup_with_mnemonic(GTK_LABEL(name_lbl), action->name);
531             gtk_misc_set_alignment((GtkMisc *) name_lbl, 0.0, 0.5);
532             gtk_container_add((GtkContainer *) item, name_lbl);
533         }
535         nr_active_object_add_listener((NRActiveObject *)action, (NRObjectEventVector *)&menu_item_event_vector, sizeof(SPActionEventVector), item);
536         if (!action->sensitive) {
537             gtk_widget_set_sensitive(item, FALSE);
538         }
540         if (action->image) {
541             sp_ui_menuitem_add_icon(item, action->image);
542         }
543         gtk_widget_set_events(item, GDK_KEY_PRESS_MASK);
544         g_signal_connect( G_OBJECT(item), "activate",
545                           G_CALLBACK(sp_ui_menu_activate), action );
547         g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select_action), action );
548         g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect_action), action );
549     }
551     gtk_widget_show(item);
552     gtk_menu_append(GTK_MENU(menu), item);
554     return item;
556 } // end of sp_ui_menu_append_item_from_verb
559 static void
560 checkitem_toggled(GtkCheckMenuItem *menuitem, gpointer user_data)
562     gchar const *pref = (gchar const *) user_data;
563     Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
565     gchar const *pref_path;
566     if (reinterpret_cast<SPDesktop*>(view)->is_fullscreen)
567         pref_path = g_strconcat("fullscreen.", pref, NULL);
568     else
569         pref_path = g_strconcat("window.", pref, NULL);
571     gboolean checked = gtk_check_menu_item_get_active(menuitem);
572     prefs_set_int_attribute(pref_path, "state", checked);
574     reinterpret_cast<SPDesktop*>(view)->layoutWidget();
577 static gboolean
578 checkitem_update(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
580     GtkCheckMenuItem *menuitem=GTK_CHECK_MENU_ITEM(widget);
582     gchar const *pref = (gchar const *) user_data;
583     Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
585     gchar const *pref_path;
586     if (static_cast<SPDesktop*>(view)->is_fullscreen)
587         pref_path = g_strconcat("fullscreen.", pref, NULL);
588     else
589         pref_path = g_strconcat("window.", pref, NULL);
591     gint ison = prefs_get_int_attribute_limited(pref_path, "state", 1, 0, 1);
593     g_signal_handlers_block_by_func(G_OBJECT(menuitem), (gpointer)(GCallback)checkitem_toggled, user_data);
594     gtk_check_menu_item_set_active(menuitem, ison);
595     g_signal_handlers_unblock_by_func(G_OBJECT(menuitem), (gpointer)(GCallback)checkitem_toggled, user_data);
597     return FALSE;
601 void
602 sp_ui_menu_append_check_item_from_verb(GtkMenu *menu, Inkscape::UI::View::View *view, gchar const *label, gchar const *tip, gchar const *pref,
603                                        void (*callback_toggle)(GtkCheckMenuItem *, gpointer user_data),
604                                        gboolean (*callback_update)(GtkWidget *widget, GdkEventExpose *event, gpointer user_data),
605                                        Inkscape::Verb *verb)
607     GtkWidget *item;
609     unsigned int shortcut = 0;
610     SPAction *action = NULL;
612     if (verb) {
613         shortcut = sp_shortcut_get_primary(verb);
614         action = verb->get_action(view);
615     }
617     if (verb && shortcut) {
618         gchar c[256];
619         sp_ui_shortcut_string(shortcut, c);
621         GtkWidget *hb = gtk_hbox_new(FALSE, 16);
623         {
624             GtkWidget *l = gtk_label_new_with_mnemonic(action ? action->name : label);
625             gtk_misc_set_alignment((GtkMisc *) l, 0.0, 0.5);
626             gtk_box_pack_start((GtkBox *) hb, l, TRUE, TRUE, 0);
627         }
629         {
630             GtkWidget *l = gtk_label_new(c);
631             gtk_misc_set_alignment((GtkMisc *) l, 1.0, 0.5);
632             gtk_box_pack_end((GtkBox *) hb, l, FALSE, FALSE, 0);
633         }
635         gtk_widget_show_all(hb);
637         item = gtk_check_menu_item_new();
638         gtk_container_add((GtkContainer *) item, hb);
639     } else {
640         GtkWidget *l = gtk_label_new_with_mnemonic(action ? action->name : label);
641         gtk_misc_set_alignment((GtkMisc *) l, 0.0, 0.5);
642         item = gtk_check_menu_item_new();
643         gtk_container_add((GtkContainer *) item, l);
644     }
645 #if 0
646     nr_active_object_add_listener((NRActiveObject *)action, (NRObjectEventVector *)&menu_item_event_vector, sizeof(SPActionEventVector), item);
647     if (!action->sensitive) {
648         gtk_widget_set_sensitive(item, FALSE);
649     }
650 #endif
651     gtk_widget_show(item);
653     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
655     g_object_set_data(G_OBJECT(item), "view", (gpointer) view);
657     g_signal_connect( G_OBJECT(item), "toggled", (GCallback) callback_toggle, (void *) pref);
658     g_signal_connect( G_OBJECT(item), "expose_event", (GCallback) callback_update, (void *) pref);
660     g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), (gpointer) (action ? action->tip : tip));
661     g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), NULL);
664 static void
665 sp_recent_open(GtkWidget *widget, gchar const *uri)
667     sp_file_open(uri, NULL);
670 static void
671 sp_file_new_from_template(GtkWidget *widget, gchar const *uri)
673     sp_file_new(uri);
676 void
677 sp_menu_append_new_templates(GtkWidget *menu, Inkscape::UI::View::View *view)
679     std::list<gchar *> sources;
680     sources.push_back( profile_path("templates") ); // first try user's local dir
681     sources.push_back( g_strdup(INKSCAPE_TEMPLATESDIR) ); // then the system templates dir
683     // Use this loop to iterate through a list of possible document locations.
684     while (!sources.empty()) {
685         gchar *dirname = sources.front();
687         if ( Inkscape::IO::file_test( dirname, (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR) ) ) {
688             GError *err = 0;
689             GDir *dir = g_dir_open(dirname, 0, &err);
691             if (dir) {
692                 for (gchar const *file = g_dir_read_name(dir); file != NULL; file = g_dir_read_name(dir)) {
693                     if (!g_str_has_suffix(file, ".svg"))
694                         continue; // skip non-svg files
696                     gchar *basename = g_path_get_basename(file);
697                     if (g_str_has_suffix(basename, ".svg") && g_str_has_prefix(basename, "default."))
698                         continue; // skip default.*.svg (i.e. default.svg and translations) - it's in the menu already
700                     gchar const *filepath = g_build_filename(dirname, file, NULL);
701                     gchar *dupfile = g_strndup(file, strlen(file) - 4);
702                     gchar *filename =  g_filename_to_utf8(dupfile,  -1, NULL, NULL, NULL);
703                     g_free(dupfile);
704                     GtkWidget *item = gtk_menu_item_new_with_label(filename);
705                     g_free(filename);
707                     gtk_widget_show(item);
708                     // how does "filepath" ever get freed?
709                     g_signal_connect(G_OBJECT(item),
710                                      "activate",
711                                      G_CALLBACK(sp_file_new_from_template),
712                                      (gpointer) filepath);
714                     if (view) {
715                         // set null tip for now; later use a description from the template file
716                         g_object_set_data(G_OBJECT(item), "view", (gpointer) view);
717                         g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), (gpointer) NULL );
718                         g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), NULL);
719                     }
721                     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
722                 }
723                 g_dir_close(dir);
724             }
725         }
727         // toss the dirname
728         g_free(dirname);
729         sources.pop_front();
730     }
733 void
734 sp_menu_append_recent_documents(GtkWidget *menu, Inkscape::UI::View::View* /* view */)
736     gchar const **recent = prefs_get_recent_files();
737     if (recent) {
738         int i;
740         for (i = 0; recent[i] != NULL; i += 2) {
741             gchar const *uri = recent[i];
742             gchar const *name = recent[i + 1];
744             GtkWidget *item = gtk_menu_item_new_with_label(name);
745             gtk_widget_show(item);
746             g_signal_connect(G_OBJECT(item),
747                              "activate",
748                              G_CALLBACK(sp_recent_open),
749                              (gpointer)uri);
750             gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
751         }
753         g_free(recent);
754     } else {
755         GtkWidget *item = gtk_menu_item_new_with_label(_("None"));
756         gtk_widget_show(item);
757         gtk_widget_set_sensitive(item, FALSE);
758         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
759     }
762 void
763 sp_ui_checkboxes_menus(GtkMenu *m, Inkscape::UI::View::View *view)
765     //sp_ui_menu_append_check_item_from_verb(m, view, _("_Menu"), _("Show or hide the menu bar"), "menu",
766     //                                       checkitem_toggled, checkitem_update, 0);
767     sp_ui_menu_append_check_item_from_verb(m, view, _("Commands Bar"), _("Show or hide the Commands bar (under the menu)"), "commands",
768                                            checkitem_toggled, checkitem_update, 0);
769     sp_ui_menu_append_check_item_from_verb(m, view, _("Tool Controls Bar"), _("Show or hide the Tool Controls bar"), "toppanel",
770                                            checkitem_toggled, checkitem_update, 0);
771     sp_ui_menu_append_check_item_from_verb(m, view, _("_Toolbox"), _("Show or hide the main toolbox (on the left)"), "toolbox",
772                                            checkitem_toggled, checkitem_update, 0);
773     sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "rulers",
774                                            checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_RULERS));
775     sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "scrollbars",
776                                            checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_SCROLLBARS));
777     sp_ui_menu_append_check_item_from_verb(m, view, _("_Statusbar"), _("Show or hide the statusbar (at the bottom of the window)"), "statusbar",
778                                            checkitem_toggled, checkitem_update, 0);
779     sp_ui_menu_append_check_item_from_verb(m, view, _("_Palette"), _("Show or hide the color palette"), "panels",
780                                            checkitem_toggled, checkitem_update, 0);
783 /** \brief  This function turns XML into a menu
784     \param  menus  This is the XML that defines the menu
785     \param  menu   Menu to be added to
786     \param  view   The View that this menu is being built for
788     This function is realitively simple as it just goes through the XML
789     and parses the individual elements.  In the case of a submenu, it
790     just calls itself recursively.  Because it is only reasonable to have
791     a couple of submenus, it is unlikely this will go more than two or
792     three times.
794     In the case of an unreconginzed verb, a menu item is made to identify
795     the verb that is missing, and display that.  The menu item is also made
796     insensitive.
797 */
798 void
799 sp_ui_build_dyn_menus(Inkscape::XML::Node *menus, GtkWidget *menu, Inkscape::UI::View::View *view)
801     if (menus == NULL) return;
802     if (menu == NULL)  return;
803     GSList *group = NULL;
805     for (Inkscape::XML::Node *menu_pntr = menus;
806          menu_pntr != NULL;
807          menu_pntr = menu_pntr->next()) {
808         if (!strcmp(menu_pntr->name(), "submenu")) {
809             if (!strcmp(menu_pntr->attribute("name"), "Effects") && !prefs_get_int_attribute("extensions", "show-effects-menu", 0)) {
810                 continue;
811             }
812             GtkWidget *mitem = gtk_menu_item_new_with_mnemonic(_(menu_pntr->attribute("name")));
813             GtkWidget *submenu = gtk_menu_new();
814             sp_ui_build_dyn_menus(menu_pntr->firstChild(), submenu, view);
815             gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), GTK_WIDGET(submenu));
816             gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
817             continue;
818         }
819         if (!strcmp(menu_pntr->name(), "verb")) {
820             gchar const *verb_name = menu_pntr->attribute("verb-id");
821             Inkscape::Verb *verb = Inkscape::Verb::getbyid(verb_name);
823             if (verb != NULL) {
824                 if (menu_pntr->attribute("radio") != NULL) {
825                     GtkWidget *item = sp_ui_menu_append_item_from_verb (GTK_MENU(menu), verb, view, true, group);
826                     group = gtk_radio_menu_item_get_group( GTK_RADIO_MENU_ITEM(item));
827                     if (menu_pntr->attribute("default") != NULL) {
828                         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
829                     }
830                 } else {
831                     sp_ui_menu_append_item_from_verb(GTK_MENU(menu), verb, view);
832                     group = NULL;
833                 }
834             } else {
835                 gchar string[120];
836                 g_snprintf(string, 120, _("Verb \"%s\" Unknown"), verb_name);
837                 string[119] = '\0'; /* may not be terminated */
838                 GtkWidget *item = gtk_menu_item_new_with_label(string);
839                 gtk_widget_set_sensitive(item, false);
840                 gtk_widget_show(item);
841                 gtk_menu_append(GTK_MENU(menu), item);
842             }
843             continue;
844         }
845         if (!strcmp(menu_pntr->name(), "separator")
846                 // This was spelt wrong in the original version
847                 // and so this is for backward compatibility.  It can
848                 // probably be dropped after the 0.44 release.
849              || !strcmp(menu_pntr->name(), "seperator")) {
850             GtkWidget *item = gtk_separator_menu_item_new();
851             gtk_widget_show(item);
852             gtk_menu_append(GTK_MENU(menu), item);
853             continue;
854         }
855         if (!strcmp(menu_pntr->name(), "template-list")) {
856             sp_menu_append_new_templates(menu, view);
857             continue;
858         }
859         if (!strcmp(menu_pntr->name(), "recent-file-list")) {
860             sp_menu_append_recent_documents(menu, view);
861             continue;
862         }
863         if (!strcmp(menu_pntr->name(), "objects-checkboxes")) {
864             sp_ui_checkboxes_menus(GTK_MENU(menu), view);
865             continue;
866         }
867     }
870 /** \brief  Build the main tool bar
871     \param  view  View to build the bar for
873     Currently the main tool bar is built as a dynamic XML menu using
874     \c sp_ui_build_dyn_menus.  This function builds the bar, and then
875     pass it to get items attached to it.
876 */
877 GtkWidget *
878 sp_ui_main_menubar(Inkscape::UI::View::View *view)
880     GtkWidget *mbar = gtk_menu_bar_new();
882     sp_ui_build_dyn_menus(inkscape_get_menus(INKSCAPE), mbar, view);
884     return mbar;
887 static void leave_group(GtkMenuItem *, SPDesktop *desktop) {
888     desktop->setCurrentLayer(SP_OBJECT_PARENT(desktop->currentLayer()));
891 static void enter_group(GtkMenuItem *mi, SPDesktop *desktop) {
892     desktop->setCurrentLayer(reinterpret_cast<SPObject *>(g_object_get_data(G_OBJECT(mi), "group")));
893     SP_DT_SELECTION(desktop)->clear();
896 GtkWidget *
897 sp_ui_context_menu(Inkscape::UI::View::View *view, SPItem *item)
899     GtkWidget *m;
900     SPDesktop *dt;
902     dt = static_cast<SPDesktop*>(view);
904     m = gtk_menu_new();
906     /* Undo and Redo */
907     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_UNDO), view);
908     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_REDO), view);
910     /* Separator */
911     sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
913     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_CUT), view);
914     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_COPY), view);
915     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_PASTE), view);
917     /* Separator */
918     sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
920     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_DUPLICATE), view);
921     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_DELETE), view);
923     /* Item menu */
924     if (item) {
925         sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
926         sp_object_menu((SPObject *) item, dt, GTK_MENU(m));
927     }
929     /* layer menu */
930     SPGroup *group=NULL;
931     if (item) {
932         if (SP_IS_GROUP(item)) {
933             group = SP_GROUP(item);
934         } else if ( item != dt->currentRoot() && SP_IS_GROUP(SP_OBJECT_PARENT(item)) ) {
935             group = SP_GROUP(SP_OBJECT_PARENT(item));
936         }
937     }
939     if (( group && group != dt->currentLayer() ) ||
940         ( dt->currentLayer() != dt->currentRoot() ) ) {
941         sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
942     }
944     if ( group && group != dt->currentLayer() ) {
945         /* TRANSLATORS: #%s is the id of the group e.g. <g id="#g7">, not a number. */
946         gchar *label=g_strdup_printf(_("Enter group #%s"), SP_OBJECT_ID(group));
947         GtkWidget *w = gtk_menu_item_new_with_label(label);
948         g_free(label);
949         g_object_set_data(G_OBJECT(w), "group", group);
950         g_signal_connect(G_OBJECT(w), "activate", GCallback(enter_group), dt);
951         gtk_widget_show(w);
952         gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
953     }
955     if ( dt->currentLayer() != dt->currentRoot() ) {
956         if ( SP_OBJECT_PARENT(dt->currentLayer()) != dt->currentRoot() ) {
957             GtkWidget *w = gtk_menu_item_new_with_label(_("Go to parent"));
958             g_signal_connect(G_OBJECT(w), "activate", GCallback(leave_group), dt);
959             gtk_widget_show(w);
960             gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
962         }
963     }
965     return m;
968 /* Drag and Drop */
969 void
970 sp_ui_drag_data_received(GtkWidget *widget,
971                          GdkDragContext *drag_context,
972                          gint x, gint y,
973                          GtkSelectionData *data,
974                          guint info,
975                          guint event_time,
976                          gpointer user_data)
978     switch (info) {
979         case APP_X_INKY_COLOR:
980         {
981             SPDesktop *desktop = SP_ACTIVE_DESKTOP;
982             int destX = 0;
983             int destY = 0;
984             gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
985             NR::Point where( sp_canvas_window_to_world( desktop->canvas, NR::Point( destX, destY ) ) );
987             SPItem *item = desktop->item_at_point( where, true );
988             if ( item )
989             {
990                 if ( data->length >= 8 ) {
991                     gchar c[64] = {0};
992                     // Careful about endian issues.
993                     guint16* dataVals = (guint16*)data->data;
994                     sp_svg_write_color( c, 64,
995                                         SP_RGBA32_U_COMPOSE(
996                                             0x0ff & (dataVals[0] >> 8),
997                                             0x0ff & (dataVals[1] >> 8),
998                                             0x0ff & (dataVals[2] >> 8),
999                                             0xff // can't have transparency in the color itself
1000                                             //0x0ff & (data->data[3] >> 8),
1001                                             ));
1002                     SPCSSAttr *css = sp_repr_css_attr_new();
1003                     sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
1005                     sp_desktop_apply_css_recursive( item, css, true );
1006                     item->updateRepr();
1008                     if ( data->length > 12 ) {
1009                         // piggie-backed palette entry info
1010                         int index = dataVals[4];
1011                         Glib::ustring palName;
1012                         for ( int i = 0; i < dataVals[5]; i++ ) {
1013                             palName += (gunichar)dataVals[6+i];
1014                         }
1016                         // Now hook in a magic tag of some sort.
1017                         if ( !palName.empty() ) {
1018                             gchar* str = g_strdup_printf("%d|", index);
1019                             palName.insert( 0, str );
1020                             g_free(str);
1021                             str = 0;
1023                             sp_object_setAttribute( SP_OBJECT(item),
1024                                                     (drag_context->action != GDK_ACTION_MOVE) ? "HOTFill":"HOTStroke",
1025                                                     palName.c_str(),
1026                                                     false );
1027                             item->updateRepr();
1028                         }
1029                     }
1031                     SPDocument *doc = SP_ACTIVE_DOCUMENT;
1032                     sp_document_done( doc );
1033                 }
1034             }
1035         }
1036         break;
1038         case APP_X_COLOR:
1039         {
1040             SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1041             int destX = 0;
1042             int destY = 0;
1043             gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
1044             NR::Point where( sp_canvas_window_to_world( desktop->canvas, NR::Point( destX, destY ) ) );
1046             SPItem *item = desktop->item_at_point( where, true );
1047             if ( item )
1048             {
1049                 if ( data->length == 8 ) {
1050                     gchar c[64] = {0};
1051                     // Careful about endian issues.
1052                     guint16* dataVals = (guint16*)data->data;
1053                     sp_svg_write_color( c, 64,
1054                                         SP_RGBA32_U_COMPOSE(
1055                                             0x0ff & (dataVals[0] >> 8),
1056                                             0x0ff & (dataVals[1] >> 8),
1057                                             0x0ff & (dataVals[2] >> 8),
1058                                             0xff // can't have transparency in the color itself
1059                                             //0x0ff & (data->data[3] >> 8),
1060                                             ));
1061                     SPCSSAttr *css = sp_repr_css_attr_new();
1062                     sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
1064                     sp_desktop_apply_css_recursive( item, css, true );
1065                     item->updateRepr();
1067                     SPDocument *doc = SP_ACTIVE_DOCUMENT;
1068                     sp_document_done( doc );
1069                 }
1070             }
1071         }
1072         break;
1074         case SVG_DATA:
1075         case SVG_XML_DATA: {
1076             gchar *svgdata = (gchar *)data->data;
1078             SPDocument *doc = SP_ACTIVE_DOCUMENT;
1080             Inkscape::XML::Document *rnewdoc = sp_repr_read_mem(svgdata, data->length, SP_SVG_NS_URI);
1082             if (rnewdoc == NULL) {
1083                 sp_ui_error_dialog(_("Could not parse SVG data"));
1084                 return;
1085             }
1087             Inkscape::XML::Node *repr = sp_repr_document_root(rnewdoc);
1088             gchar const *style = repr->attribute("style");
1090             Inkscape::XML::Node *newgroup = sp_repr_new("svg:g");
1091             newgroup->setAttribute("style", style);
1093             for (Inkscape::XML::Node *child = repr->firstChild(); child != NULL; child = child->next()) {
1094                 Inkscape::XML::Node *newchild = child->duplicate();
1095                 newgroup->appendChild(newchild);
1096             }
1098             Inkscape::GC::release(rnewdoc);
1100             SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1101             // Add it to the current layer
1103             // Greg's edits to add intelligent positioning of svg drops
1104             SPObject *new_obj = NULL;
1105             new_obj = desktop->currentLayer()->appendChildRepr(newgroup);
1107             Inkscape::Selection *selection = SP_DT_SELECTION(desktop);
1108             selection->set(SP_ITEM(new_obj));
1109             // To move the imported object, we must temporarily set the "transform pattern with
1110             // object" option.
1111             {
1112                 int const saved_pref = prefs_get_int_attribute("options.transform", "pattern", 1);
1113                 prefs_set_int_attribute("options.transform", "pattern", 1);
1114                 sp_document_ensure_up_to_date(SP_DT_DOCUMENT(desktop));
1115                 NR::Point m( desktop->point() - selection->bounds().midpoint() );
1116                 sp_selection_move_relative(selection, m);
1117                 prefs_set_int_attribute("options.transform", "pattern", saved_pref);
1118             }
1120             Inkscape::GC::release(newgroup);
1121             sp_document_done(doc);
1122             break;
1123         }
1125         case URI_LIST: {
1126             gchar *uri = (gchar *)data->data;
1127             sp_ui_import_files(uri);
1128             break;
1129         }
1131         case PNG_DATA:
1132         case JPEG_DATA:
1133         case IMAGE_DATA: {
1134             char tmp[1024];
1136             StringOutputStream outs;
1137             Base64OutputStream b64out(outs);
1138             b64out.setColumnWidth(0);
1140             SPDocument *doc = SP_ACTIVE_DOCUMENT;
1142             Inkscape::XML::Node *newImage = sp_repr_new("svg:image");
1144             for ( int i = 0; i < data->length; i++ ) {
1145                 b64out.put( data->data[i] );
1146             }
1147             b64out.close();
1150             Glib::ustring str = outs.getString();
1152             snprintf( tmp, sizeof(tmp), "data:%s;base64,", gdk_atom_name(data->type) );
1153             str.insert( 0, tmp );
1154             newImage->setAttribute("xlink:href", str.c_str());
1156             GError *error = NULL;
1157             GdkPixbufLoader *loader = gdk_pixbuf_loader_new_with_mime_type( gdk_atom_name(data->type), &error );
1158             if ( loader ) {
1159                 error = NULL;
1160                 if ( gdk_pixbuf_loader_write( loader, data->data, data->length, &error) ) {
1161                     GdkPixbuf *pbuf = gdk_pixbuf_loader_get_pixbuf(loader);
1162                     if ( pbuf ) {
1163                         int width = gdk_pixbuf_get_width(pbuf);
1164                         int height = gdk_pixbuf_get_height(pbuf);
1165                         snprintf( tmp, sizeof(tmp), "%d", width );
1166                         newImage->setAttribute("width", tmp);
1168                         snprintf( tmp, sizeof(tmp), "%d", height );
1169                         newImage->setAttribute("height", tmp);
1170                     }
1171                 }
1172             }
1174             SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1176             // Add it to the current layer
1177             desktop->currentLayer()->appendChildRepr(newImage);
1179             Inkscape::GC::release(newImage);
1180             sp_document_done( doc );
1181             break;
1182         }
1183     }
1186 static void
1187 sp_ui_import_files(gchar *buffer)
1189     GList *list = gnome_uri_list_extract_filenames(buffer);
1190     if (!list)
1191         return;
1192     g_list_foreach(list, sp_ui_import_one_file_with_check, NULL);
1193     g_list_foreach(list, (GFunc) g_free, NULL);
1194     g_list_free(list);
1197 static void
1198 sp_ui_import_one_file_with_check(gpointer filename, gpointer unused)
1200     if (filename) {
1201         if (strlen((char const *)filename) > 2)
1202             sp_ui_import_one_file((char const *)filename);
1203     }
1206 static void
1207 sp_ui_import_one_file(char const *filename)
1209     SPDocument *doc = SP_ACTIVE_DOCUMENT;
1210     if (!doc) return;
1212     if (filename == NULL) return;
1214     // Pass off to common implementation
1215     // TODO might need to get the proper type of Inkscape::Extension::Extension
1216     file_import( doc, filename, NULL );
1219 void
1220 sp_ui_error_dialog(gchar const *message)
1222     GtkWidget *dlg;
1223     gchar *safeMsg = Inkscape::IO::sanitizeString(message);
1225     dlg = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
1226                                  GTK_BUTTONS_CLOSE, safeMsg);
1227     sp_transientize(dlg);
1228     gtk_window_set_resizable(GTK_WINDOW(dlg), FALSE);
1229     gtk_dialog_run(GTK_DIALOG(dlg));
1230     gtk_widget_destroy(dlg);
1231     g_free(safeMsg);
1234 bool
1235 sp_ui_overwrite_file(gchar const *filename)
1237     bool return_value = FALSE;
1238     GtkWidget *dialog;
1239     GtkWidget *hbox;
1240     GtkWidget *boxdata;
1241     gchar *title;
1242     gchar *text;
1244     if (Inkscape::IO::file_test(filename, G_FILE_TEST_EXISTS)) {
1246         title = g_strdup_printf(_("Overwrite %s"), filename);
1247         dialog = gtk_dialog_new_with_buttons(title,
1248                                              NULL,
1249                                              (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
1250                                              GTK_STOCK_NO,
1251                                              GTK_RESPONSE_NO,
1252                                              GTK_STOCK_YES,
1253                                              GTK_RESPONSE_YES,
1254                                              NULL);
1255         gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_YES);
1257         sp_transientize(dialog);
1258         gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
1260         hbox = gtk_hbox_new(FALSE, 5);
1261         boxdata = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
1262         gtk_widget_show(boxdata);
1263         gtk_box_pack_start(GTK_BOX(hbox), boxdata, TRUE, TRUE, 5);
1264         text = g_strdup_printf(_("The file %s already exists.  Do you want to overwrite that file with the current document?"), filename);
1265         boxdata = gtk_label_new(text);
1266         gtk_label_set_line_wrap(GTK_LABEL(boxdata), TRUE);
1267         gtk_widget_show(boxdata);
1268         gtk_box_pack_start(GTK_BOX(hbox), boxdata, FALSE, FALSE, 5);
1269         gtk_widget_show(hbox);
1270         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, TRUE, TRUE, 5);
1272         if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES) {
1273             return_value = TRUE;
1274         } else {
1275             return_value = FALSE;
1276         }
1278         gtk_widget_destroy(dialog);
1279         g_free(title);
1280         g_free(text);
1281     } else {
1282         return_value = TRUE;
1283     }
1285     return return_value;
1288 static void
1289 sp_ui_menu_item_set_sensitive(SPAction *action, unsigned int sensitive, void *data)
1291     return gtk_widget_set_sensitive(GTK_WIDGET(data), sensitive);
1294 /*
1295   Local Variables:
1296   mode:c++
1297   c-file-style:"stroustrup"
1298   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1299   indent-tabs-mode:nil
1300   fill-column:99
1301   End:
1302 */
1303 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :