Code

Renaming temp non-standard attributes
[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 > 14 ) {
1009                         int flags = dataVals[4];
1011                         // piggie-backed palette entry info
1012                         int index = dataVals[5];
1013                         Glib::ustring palName;
1014                         for ( int i = 0; i < dataVals[6]; i++ ) {
1015                             palName += (gunichar)dataVals[7+i];
1016                         }
1018                         // Now hook in a magic tag of some sort.
1019                         if ( !palName.empty() && (flags & 1) ) {
1020                             gchar* str = g_strdup_printf("%d|", index);
1021                             palName.insert( 0, str );
1022                             g_free(str);
1023                             str = 0;
1025                             sp_object_setAttribute( SP_OBJECT(item),
1026                                                     (drag_context->action != GDK_ACTION_MOVE) ? "inkscape:x-fill-tag":"inkscape:x-stroke-tag",
1027                                                     palName.c_str(),
1028                                                     false );
1029                             item->updateRepr();
1030                         }
1031                     }
1033                     SPDocument *doc = SP_ACTIVE_DOCUMENT;
1034                     sp_document_done( doc );
1035                 }
1036             }
1037         }
1038         break;
1040         case APP_X_COLOR:
1041         {
1042             SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1043             int destX = 0;
1044             int destY = 0;
1045             gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
1046             NR::Point where( sp_canvas_window_to_world( desktop->canvas, NR::Point( destX, destY ) ) );
1048             SPItem *item = desktop->item_at_point( where, true );
1049             if ( item )
1050             {
1051                 if ( data->length == 8 ) {
1052                     gchar c[64] = {0};
1053                     // Careful about endian issues.
1054                     guint16* dataVals = (guint16*)data->data;
1055                     sp_svg_write_color( c, 64,
1056                                         SP_RGBA32_U_COMPOSE(
1057                                             0x0ff & (dataVals[0] >> 8),
1058                                             0x0ff & (dataVals[1] >> 8),
1059                                             0x0ff & (dataVals[2] >> 8),
1060                                             0xff // can't have transparency in the color itself
1061                                             //0x0ff & (data->data[3] >> 8),
1062                                             ));
1063                     SPCSSAttr *css = sp_repr_css_attr_new();
1064                     sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
1066                     sp_desktop_apply_css_recursive( item, css, true );
1067                     item->updateRepr();
1069                     SPDocument *doc = SP_ACTIVE_DOCUMENT;
1070                     sp_document_done( doc );
1071                 }
1072             }
1073         }
1074         break;
1076         case SVG_DATA:
1077         case SVG_XML_DATA: {
1078             gchar *svgdata = (gchar *)data->data;
1080             SPDocument *doc = SP_ACTIVE_DOCUMENT;
1082             Inkscape::XML::Document *rnewdoc = sp_repr_read_mem(svgdata, data->length, SP_SVG_NS_URI);
1084             if (rnewdoc == NULL) {
1085                 sp_ui_error_dialog(_("Could not parse SVG data"));
1086                 return;
1087             }
1089             Inkscape::XML::Node *repr = sp_repr_document_root(rnewdoc);
1090             gchar const *style = repr->attribute("style");
1092             Inkscape::XML::Node *newgroup = sp_repr_new("svg:g");
1093             newgroup->setAttribute("style", style);
1095             for (Inkscape::XML::Node *child = repr->firstChild(); child != NULL; child = child->next()) {
1096                 Inkscape::XML::Node *newchild = child->duplicate();
1097                 newgroup->appendChild(newchild);
1098             }
1100             Inkscape::GC::release(rnewdoc);
1102             SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1103             // Add it to the current layer
1105             // Greg's edits to add intelligent positioning of svg drops
1106             SPObject *new_obj = NULL;
1107             new_obj = desktop->currentLayer()->appendChildRepr(newgroup);
1109             Inkscape::Selection *selection = SP_DT_SELECTION(desktop);
1110             selection->set(SP_ITEM(new_obj));
1111             // To move the imported object, we must temporarily set the "transform pattern with
1112             // object" option.
1113             {
1114                 int const saved_pref = prefs_get_int_attribute("options.transform", "pattern", 1);
1115                 prefs_set_int_attribute("options.transform", "pattern", 1);
1116                 sp_document_ensure_up_to_date(SP_DT_DOCUMENT(desktop));
1117                 NR::Point m( desktop->point() - selection->bounds().midpoint() );
1118                 sp_selection_move_relative(selection, m);
1119                 prefs_set_int_attribute("options.transform", "pattern", saved_pref);
1120             }
1122             Inkscape::GC::release(newgroup);
1123             sp_document_done(doc);
1124             break;
1125         }
1127         case URI_LIST: {
1128             gchar *uri = (gchar *)data->data;
1129             sp_ui_import_files(uri);
1130             break;
1131         }
1133         case PNG_DATA:
1134         case JPEG_DATA:
1135         case IMAGE_DATA: {
1136             char tmp[1024];
1138             StringOutputStream outs;
1139             Base64OutputStream b64out(outs);
1140             b64out.setColumnWidth(0);
1142             SPDocument *doc = SP_ACTIVE_DOCUMENT;
1144             Inkscape::XML::Node *newImage = sp_repr_new("svg:image");
1146             for ( int i = 0; i < data->length; i++ ) {
1147                 b64out.put( data->data[i] );
1148             }
1149             b64out.close();
1152             Glib::ustring str = outs.getString();
1154             snprintf( tmp, sizeof(tmp), "data:%s;base64,", gdk_atom_name(data->type) );
1155             str.insert( 0, tmp );
1156             newImage->setAttribute("xlink:href", str.c_str());
1158             GError *error = NULL;
1159             GdkPixbufLoader *loader = gdk_pixbuf_loader_new_with_mime_type( gdk_atom_name(data->type), &error );
1160             if ( loader ) {
1161                 error = NULL;
1162                 if ( gdk_pixbuf_loader_write( loader, data->data, data->length, &error) ) {
1163                     GdkPixbuf *pbuf = gdk_pixbuf_loader_get_pixbuf(loader);
1164                     if ( pbuf ) {
1165                         int width = gdk_pixbuf_get_width(pbuf);
1166                         int height = gdk_pixbuf_get_height(pbuf);
1167                         snprintf( tmp, sizeof(tmp), "%d", width );
1168                         newImage->setAttribute("width", tmp);
1170                         snprintf( tmp, sizeof(tmp), "%d", height );
1171                         newImage->setAttribute("height", tmp);
1172                     }
1173                 }
1174             }
1176             SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1178             // Add it to the current layer
1179             desktop->currentLayer()->appendChildRepr(newImage);
1181             Inkscape::GC::release(newImage);
1182             sp_document_done( doc );
1183             break;
1184         }
1185     }
1188 static void
1189 sp_ui_import_files(gchar *buffer)
1191     GList *list = gnome_uri_list_extract_filenames(buffer);
1192     if (!list)
1193         return;
1194     g_list_foreach(list, sp_ui_import_one_file_with_check, NULL);
1195     g_list_foreach(list, (GFunc) g_free, NULL);
1196     g_list_free(list);
1199 static void
1200 sp_ui_import_one_file_with_check(gpointer filename, gpointer unused)
1202     if (filename) {
1203         if (strlen((char const *)filename) > 2)
1204             sp_ui_import_one_file((char const *)filename);
1205     }
1208 static void
1209 sp_ui_import_one_file(char const *filename)
1211     SPDocument *doc = SP_ACTIVE_DOCUMENT;
1212     if (!doc) return;
1214     if (filename == NULL) return;
1216     // Pass off to common implementation
1217     // TODO might need to get the proper type of Inkscape::Extension::Extension
1218     file_import( doc, filename, NULL );
1221 void
1222 sp_ui_error_dialog(gchar const *message)
1224     GtkWidget *dlg;
1225     gchar *safeMsg = Inkscape::IO::sanitizeString(message);
1227     dlg = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
1228                                  GTK_BUTTONS_CLOSE, safeMsg);
1229     sp_transientize(dlg);
1230     gtk_window_set_resizable(GTK_WINDOW(dlg), FALSE);
1231     gtk_dialog_run(GTK_DIALOG(dlg));
1232     gtk_widget_destroy(dlg);
1233     g_free(safeMsg);
1236 bool
1237 sp_ui_overwrite_file(gchar const *filename)
1239     bool return_value = FALSE;
1240     GtkWidget *dialog;
1241     GtkWidget *hbox;
1242     GtkWidget *boxdata;
1243     gchar *title;
1244     gchar *text;
1246     if (Inkscape::IO::file_test(filename, G_FILE_TEST_EXISTS)) {
1248         title = g_strdup_printf(_("Overwrite %s"), filename);
1249         dialog = gtk_dialog_new_with_buttons(title,
1250                                              NULL,
1251                                              (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
1252                                              GTK_STOCK_NO,
1253                                              GTK_RESPONSE_NO,
1254                                              GTK_STOCK_YES,
1255                                              GTK_RESPONSE_YES,
1256                                              NULL);
1257         gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_YES);
1259         sp_transientize(dialog);
1260         gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
1262         hbox = gtk_hbox_new(FALSE, 5);
1263         boxdata = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
1264         gtk_widget_show(boxdata);
1265         gtk_box_pack_start(GTK_BOX(hbox), boxdata, TRUE, TRUE, 5);
1266         text = g_strdup_printf(_("The file %s already exists.  Do you want to overwrite that file with the current document?"), filename);
1267         boxdata = gtk_label_new(text);
1268         gtk_label_set_line_wrap(GTK_LABEL(boxdata), TRUE);
1269         gtk_widget_show(boxdata);
1270         gtk_box_pack_start(GTK_BOX(hbox), boxdata, FALSE, FALSE, 5);
1271         gtk_widget_show(hbox);
1272         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, TRUE, TRUE, 5);
1274         if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES) {
1275             return_value = TRUE;
1276         } else {
1277             return_value = FALSE;
1278         }
1280         gtk_widget_destroy(dialog);
1281         g_free(title);
1282         g_free(text);
1283     } else {
1284         return_value = TRUE;
1285     }
1287     return return_value;
1290 static void
1291 sp_ui_menu_item_set_sensitive(SPAction *action, unsigned int sensitive, void *data)
1293     return gtk_widget_set_sensitive(GTK_WIDGET(data), sensitive);
1296 /*
1297   Local Variables:
1298   mode:c++
1299   c-file-style:"stroustrup"
1300   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1301   indent-tabs-mode:nil
1302   fill-column:99
1303   End:
1304 */
1305 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :