Code

New file. use for building with gtk28
[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 "ui/context-menu.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 #if ENABLE_LCMS
58 #include "lcms.h"
59 #endif // ENABLE_LCMS
60 #include "display/sp-canvas.h"
61 #include "color.h"
62 #include "svg/svg-color.h"
63 #include "desktop-style.h"
64 #include "style.h"
67 using Inkscape::IO::StringOutputStream;
68 using Inkscape::IO::Base64OutputStream;
70 /* forward declaration */
71 static gint sp_ui_delete(GtkWidget *widget, GdkEvent *event, Inkscape::UI::View::View *view);
73 /* Drag and Drop */
74 typedef enum {
75     URI_LIST,
76     SVG_XML_DATA,
77     SVG_DATA,
78     PNG_DATA,
79     JPEG_DATA,
80     IMAGE_DATA,
81     APP_X_INKY_COLOR,
82     APP_X_COLOR
83 } ui_drop_target_info;
85 static GtkTargetEntry ui_drop_target_entries [] = {
86     {"text/uri-list", 0, URI_LIST},
87     {"image/svg+xml", 0, SVG_XML_DATA},
88     {"image/svg",     0, SVG_DATA},
89     {"image/png",     0, PNG_DATA},
90     {"image/jpeg",    0, JPEG_DATA},
91 #if ENABLE_MAGIC_COLORS
92     {"application/x-inkscape-color", 0, APP_X_INKY_COLOR},
93 #endif // ENABLE_MAGIC_COLORS
94     {"application/x-color", 0, APP_X_COLOR}
95 };
97 static GtkTargetEntry *completeDropTargets = 0;
98 static int completeDropTargetsCount = 0;
100 #define ENTRIES_SIZE(n) sizeof(n)/sizeof(n[0])
101 static guint nui_drop_target_entries = ENTRIES_SIZE(ui_drop_target_entries);
102 static void sp_ui_import_files(gchar *buffer);
103 static void sp_ui_import_one_file(char const *filename);
104 static void sp_ui_import_one_file_with_check(gpointer filename, gpointer unused);
105 static void sp_ui_drag_data_received(GtkWidget *widget,
106                                      GdkDragContext *drag_context,
107                                      gint x, gint y,
108                                      GtkSelectionData *data,
109                                      guint info,
110                                      guint event_time,
111                                      gpointer user_data);
112 static void sp_ui_menu_item_set_sensitive(SPAction *action,
113                                           unsigned int sensitive,
114                                           void *data);
115 static void sp_ui_menu_item_set_name(SPAction *action, 
116                                      Glib::ustring name,
117                                      void *data);
119 SPActionEventVector menu_item_event_vector = {
120     {NULL},
121     NULL,
122     NULL, /* set_active */
123     sp_ui_menu_item_set_sensitive, /* set_sensitive */
124     NULL, /* set_shortcut */
125     sp_ui_menu_item_set_name /* set_name */
126 };
128 void
129 sp_create_window(SPViewWidget *vw, gboolean editable)
131     g_return_if_fail(vw != NULL);
132     g_return_if_fail(SP_IS_VIEW_WIDGET(vw));
134     GtkWidget *w = sp_window_new("", TRUE);
136     if (editable) {
137       g_object_set_data(G_OBJECT(vw), "window", w);
138       reinterpret_cast<SPDesktopWidget*>(vw)->window =
139         static_cast<GtkWindow*>((void*)w);
140     }
142     if (editable) {
143         /* fixme: */
144         gtk_window_set_default_size((GtkWindow *) w, 640, 480);
145         g_object_set_data(G_OBJECT(w), "desktop", SP_DESKTOP_WIDGET(vw)->desktop);
146         g_object_set_data(G_OBJECT(w), "desktopwidget", vw);
147         g_signal_connect(G_OBJECT(w), "delete_event", G_CALLBACK(sp_ui_delete), vw->view);
148         g_signal_connect(G_OBJECT(w), "focus_in_event", G_CALLBACK(sp_desktop_widget_set_focus), vw);
149     } else {
150         gtk_window_set_policy(GTK_WINDOW(w), TRUE, TRUE, TRUE);
151     }
153     gtk_container_add(GTK_CONTAINER(w), GTK_WIDGET(vw));
154     gtk_widget_show(GTK_WIDGET(vw));
156     if ( completeDropTargets == 0 || completeDropTargetsCount == 0 )
157     {
158         std::vector<gchar*> types;
160         GSList *list = gdk_pixbuf_get_formats();
161         while ( list ) {
162             int i = 0;
163             GdkPixbufFormat *one = (GdkPixbufFormat*)list->data;
164             gchar** typesXX = gdk_pixbuf_format_get_mime_types(one);
165             for ( i = 0; typesXX[i]; i++ ) {
166                 types.push_back(g_strdup(typesXX[i]));
167             }
168             g_strfreev(typesXX);
170             list = g_slist_next(list);
171         }
172         completeDropTargetsCount = nui_drop_target_entries + types.size();
173         completeDropTargets = new GtkTargetEntry[completeDropTargetsCount];
174         for ( int i = 0; i < (int)nui_drop_target_entries; i++ ) {
175             completeDropTargets[i] = ui_drop_target_entries[i];
176         }
177         int pos = nui_drop_target_entries;
179         for (std::vector<gchar*>::iterator it = types.begin() ; it != types.end() ; it++) {
180             completeDropTargets[pos].target = *it;
181             completeDropTargets[pos].flags = 0;
182             completeDropTargets[pos].info = IMAGE_DATA;
183             pos++;
184         }
185     }
187     gtk_drag_dest_set(w,
188                       GTK_DEST_DEFAULT_ALL,
189                       completeDropTargets,
190                       completeDropTargetsCount,
191                       GdkDragAction(GDK_ACTION_COPY | GDK_ACTION_MOVE));
192     g_signal_connect(G_OBJECT(w),
193                      "drag_data_received",
194                      G_CALLBACK(sp_ui_drag_data_received),
195                      NULL);
196     gtk_widget_show(w);
198     // needed because the first ACTIVATE_DESKTOP was sent when there was no window yet
199     inkscape_reactivate_desktop(SP_DESKTOP_WIDGET(vw)->desktop);
202 void
203 sp_ui_new_view()
205     SPDocument *document;
206     SPViewWidget *dtw;
208     document = SP_ACTIVE_DOCUMENT;
209     if (!document) return;
211     dtw = sp_desktop_widget_new(sp_document_namedview(document, NULL));
212     g_return_if_fail(dtw != NULL);
214     sp_create_window(dtw, TRUE);
215     sp_namedview_window_from_document(static_cast<SPDesktop*>(dtw->view));
218 /* TODO: not yet working */
219 /* To be re-enabled (by adding to menu) once it works. */
220 void
221 sp_ui_new_view_preview()
223     SPDocument *document;
224     SPViewWidget *dtw;
226     document = SP_ACTIVE_DOCUMENT;
227     if (!document) return;
229     dtw = (SPViewWidget *) sp_svg_view_widget_new(document);
230     g_return_if_fail(dtw != NULL);
231     sp_svg_view_widget_set_resize(SP_SVG_VIEW_WIDGET(dtw), TRUE, 400.0, 400.0);
233     sp_create_window(dtw, FALSE);
236 /**
237  * \param widget unused
238  */
239 void
240 sp_ui_close_view(GtkWidget *widget)
242     if (SP_ACTIVE_DESKTOP == NULL) {
243         return;
244     }
245     if ((SP_ACTIVE_DESKTOP)->shutdown()) {
246         return;
247     }
248     SP_ACTIVE_DESKTOP->destroyWidget();
252 /**
253  *  sp_ui_close_all
254  *
255  *  This function is called to exit the program, and iterates through all
256  *  open document view windows, attempting to close each in turn.  If the
257  *  view has unsaved information, the user will be prompted to save,
258  *  discard, or cancel.
259  *
260  *  Returns FALSE if the user cancels the close_all operation, TRUE
261  *  otherwise.
262  */
263 unsigned int
264 sp_ui_close_all(void)
266     /* Iterate through all the windows, destroying each in the order they
267        become active */
268     while (SP_ACTIVE_DESKTOP) {
269         if ((SP_ACTIVE_DESKTOP)->shutdown()) {
270             /* The user cancelled the operation, so end doing the close */
271             return FALSE;
272         }
273         SP_ACTIVE_DESKTOP->destroyWidget();
274     }
276     return TRUE;
279 static gint
280 sp_ui_delete(GtkWidget *widget, GdkEvent *event, Inkscape::UI::View::View *view)
282     return view->shutdown();
285 /*
286  * Some day when the right-click menus are ready to start working
287  * smarter with the verbs, we'll need to change this NULL being
288  * sent to sp_action_perform to something useful, or set some kind
289  * of global "right-clicked position" variable for actions to
290  * investigate when they're called.
291  */
292 static void
293 sp_ui_menu_activate(void *object, SPAction *action)
295     sp_action_perform(action, NULL);
298 static void
299 sp_ui_menu_select_action(void *object, SPAction *action)
301     action->view->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, action->tip);
304 static void
305 sp_ui_menu_deselect_action(void *object, SPAction *action)
307     action->view->tipsMessageContext()->clear();
310 static void
311 sp_ui_menu_select(gpointer object, gpointer tip)
313     Inkscape::UI::View::View *view = static_cast<Inkscape::UI::View::View*> (g_object_get_data(G_OBJECT(object), "view"));
314     view->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, (gchar *)tip);
317 static void
318 sp_ui_menu_deselect(gpointer object)
320     Inkscape::UI::View::View *view = static_cast<Inkscape::UI::View::View*>  (g_object_get_data(G_OBJECT(object), "view"));
321     view->tipsMessageContext()->clear();
324 /**
325  * sp_ui_menuitem_add_icon
326  *
327  * Creates and attaches a scaled icon to the given menu item.
328  *
329  */
330 void
331 sp_ui_menuitem_add_icon( GtkWidget *item, gchar *icon_name )
333     GtkWidget *icon;
335     icon = sp_icon_new( Inkscape::ICON_SIZE_MENU, icon_name );
336     gtk_widget_show(icon);
337     gtk_image_menu_item_set_image((GtkImageMenuItem *) item, icon);
338 } // end of sp_ui_menu_add_icon
340 /**
341  * sp_ui_menu_append_item
342  *
343  * Appends a UI item with specific info for Inkscape/Sodipodi.
344  *
345  */
346 static GtkWidget *
347 sp_ui_menu_append_item( GtkMenu *menu, gchar const *stock,
348                         gchar const *label, gchar const *tip, Inkscape::UI::View::View *view, GCallback callback,
349                         gpointer data, gboolean with_mnemonic = TRUE )
351     GtkWidget *item;
353     if (stock) {
354         item = gtk_image_menu_item_new_from_stock(stock, NULL);
355     } else if (label) {
356         item = (with_mnemonic)
357             ? gtk_image_menu_item_new_with_mnemonic(label) :
358             gtk_image_menu_item_new_with_label(label);
359     } else {
360         item = gtk_separator_menu_item_new();
361     }
363     gtk_widget_show(item);
365     if (callback) {
366         g_signal_connect(G_OBJECT(item), "activate", callback, data);
367     }
369     if (tip && view) {
370         g_object_set_data(G_OBJECT(item), "view", (gpointer) view);
371         g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), (gpointer) tip );
372         g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), NULL);
373     }
375     gtk_menu_append(GTK_MENU(menu), item);
377     return item;
379 } // end of sp_ui_menu_append_item()
381 /**
382 \brief  a wrapper around gdk_keyval_name producing (when possible) characters, not names
383  */
384 static gchar const *
385 sp_key_name(guint keyval)
387     /* TODO: Compare with the definition of gtk_accel_label_refetch in gtk/gtkaccellabel.c (or
388        simply use GtkAccelLabel as the TODO comment in sp_ui_shortcut_string suggests). */
389     gchar const *n = gdk_keyval_name(gdk_keyval_to_upper(keyval));
391     if      (!strcmp(n, "asciicircum"))  return "^";
392     else if (!strcmp(n, "parenleft"  ))  return "(";
393     else if (!strcmp(n, "parenright" ))  return ")";
394     else if (!strcmp(n, "plus"       ))  return "+";
395     else if (!strcmp(n, "minus"      ))  return "-";
396     else if (!strcmp(n, "asterisk"   ))  return "*";
397     else if (!strcmp(n, "KP_Multiply"))  return "*";
398     else if (!strcmp(n, "Delete"     ))  return "Del";
399     else if (!strcmp(n, "Page_Up"    ))  return "PgUp";
400     else if (!strcmp(n, "Page_Down"  ))  return "PgDn";
401     else if (!strcmp(n, "grave"      ))  return "`";
402     else if (!strcmp(n, "numbersign" ))  return "#";
403     else if (!strcmp(n, "bar" ))  return "|";
404     else if (!strcmp(n, "slash" ))  return "/";
405     else if (!strcmp(n, "exclam" ))  return "!";
406     else return n;
410 /**
411  * \param shortcut A GDK keyval OR'd with SP_SHORTCUT_blah_MASK values.
412  * \param c Points to a buffer at least 256 bytes long.
413  */
414 void
415 sp_ui_shortcut_string(unsigned const shortcut, gchar *const c)
417     /* TODO: This function shouldn't exist.  Our callers should use GtkAccelLabel instead of
418      * a generic GtkLabel containing this string, and should call gtk_widget_add_accelerator.
419      * Will probably need to change sp_shortcut_invoke callers.
420      *
421      * The existing gtk_label_new_with_mnemonic call can be replaced with
422      * g_object_new(GTK_TYPE_ACCEL_LABEL, NULL) followed by
423      * gtk_label_set_text_with_mnemonic(lbl, str).
424      */
425     static GtkAccelLabelClass const &accel_lbl_cls
426         = *(GtkAccelLabelClass const *) g_type_class_peek_static(GTK_TYPE_ACCEL_LABEL);
428     struct { unsigned test; char const *name; } const modifier_tbl[] = {
429         { SP_SHORTCUT_SHIFT_MASK,   accel_lbl_cls.mod_name_shift   },
430         { SP_SHORTCUT_CONTROL_MASK, accel_lbl_cls.mod_name_control },
431         { SP_SHORTCUT_ALT_MASK,     accel_lbl_cls.mod_name_alt     }
432     };
434     gchar *p = c;
435     gchar *end = p + 256;
437     for (unsigned i = 0; i < G_N_ELEMENTS(modifier_tbl); ++i) {
438         if ((shortcut & modifier_tbl[i].test)
439             && (p < end))
440         {
441             p += g_snprintf(p, end - p, "%s%s",
442                             modifier_tbl[i].name,
443                             accel_lbl_cls.mod_separator);
444         }
445     }
446     if (p < end) {
447         p += g_snprintf(p, end - p, "%s", sp_key_name(shortcut & 0xffffff));
448     }
449     end[-1] = '\0';  // snprintf doesn't guarantee to nul-terminate the string.
452 void
453 sp_ui_dialog_title_string(Inkscape::Verb *verb, gchar *c)
455     SPAction     *action;
456     unsigned int shortcut;
457     gchar        *s;
458     gchar        key[256];
459     gchar        *atitle;
461     action = verb->get_action(NULL);
462     if (!action)
463         return;
465     atitle = sp_action_get_title(action);
467     s = g_stpcpy(c, atitle);
469     g_free(atitle);
471     shortcut = sp_shortcut_get_primary(verb);
472     if (shortcut) {
473         s = g_stpcpy(s, " (");
474         sp_ui_shortcut_string(shortcut, key);
475         s = g_stpcpy(s, key);
476         s = g_stpcpy(s, ")");
477     }
481 /**
482  * sp_ui_menu_append_item_from_verb
483  *
484  * Appends a custom menu UI from a verb.
485  *
486  */
488 static GtkWidget *
489 sp_ui_menu_append_item_from_verb(GtkMenu *menu, Inkscape::Verb *verb, Inkscape::UI::View::View *view, bool radio = false, GSList *group = NULL)
491     SPAction *action;
492     GtkWidget *item;
494     if (verb->get_code() == SP_VERB_NONE) {
496         item = gtk_separator_menu_item_new();
498     } else {
499         unsigned int shortcut;
501         action = verb->get_action(view);
503         if (!action) return NULL;
505         shortcut = sp_shortcut_get_primary(verb);
506         if (shortcut) {
507             gchar c[256];
508             sp_ui_shortcut_string(shortcut, c);
509             GtkWidget *const hb = gtk_hbox_new(FALSE, 16);
510             GtkWidget *const name_lbl = gtk_label_new("");
511             gtk_label_set_markup_with_mnemonic(GTK_LABEL(name_lbl), action->name);
512             gtk_misc_set_alignment((GtkMisc *) name_lbl, 0.0, 0.5);
513             gtk_box_pack_start((GtkBox *) hb, name_lbl, TRUE, TRUE, 0);
514             GtkWidget *const accel_lbl = gtk_label_new(c);
515             gtk_misc_set_alignment((GtkMisc *) accel_lbl, 1.0, 0.5);
516             gtk_box_pack_end((GtkBox *) hb, accel_lbl, FALSE, FALSE, 0);
517             gtk_widget_show_all(hb);
518             if (radio) {
519                 item = gtk_radio_menu_item_new (group);
520             } else {
521                 item = gtk_image_menu_item_new();
522             }
523             gtk_container_add((GtkContainer *) item, hb);
524         } else {
525             if (radio) {
526                 item = gtk_radio_menu_item_new (group);
527             } else {
528                 item = gtk_image_menu_item_new ();
529             }
530             GtkWidget *const name_lbl = gtk_label_new("");
531             gtk_label_set_markup_with_mnemonic(GTK_LABEL(name_lbl), action->name);
532             gtk_misc_set_alignment((GtkMisc *) name_lbl, 0.0, 0.5);
533             gtk_container_add((GtkContainer *) item, name_lbl);
534         }
536         nr_active_object_add_listener((NRActiveObject *)action, (NRObjectEventVector *)&menu_item_event_vector, sizeof(SPActionEventVector), item);
537         if (!action->sensitive) {
538             gtk_widget_set_sensitive(item, FALSE);
539         }
541         if (action->image) {
542             sp_ui_menuitem_add_icon(item, action->image);
543         }
544         gtk_widget_set_events(item, GDK_KEY_PRESS_MASK);
545         g_signal_connect( G_OBJECT(item), "activate",
546                           G_CALLBACK(sp_ui_menu_activate), action );
548         g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select_action), action );
549         g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect_action), action );
550     }
552     gtk_widget_show(item);
553     gtk_menu_append(GTK_MENU(menu), item);
555     return item;
557 } // end of sp_ui_menu_append_item_from_verb
560 static void
561 checkitem_toggled(GtkCheckMenuItem *menuitem, gpointer user_data)
563     gchar const *pref = (gchar const *) user_data;
564     Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
566     gchar const *pref_path;
567     if (reinterpret_cast<SPDesktop*>(view)->is_fullscreen)
568         pref_path = g_strconcat("fullscreen.", pref, NULL);
569     else
570         pref_path = g_strconcat("window.", pref, NULL);
572     gboolean checked = gtk_check_menu_item_get_active(menuitem);
573     prefs_set_int_attribute(pref_path, "state", checked);
575     reinterpret_cast<SPDesktop*>(view)->layoutWidget();
578 static gboolean
579 checkitem_update(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
581     GtkCheckMenuItem *menuitem=GTK_CHECK_MENU_ITEM(widget);
583     gchar const *pref = (gchar const *) user_data;
584     Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
586     gchar const *pref_path;
587     if (static_cast<SPDesktop*>(view)->is_fullscreen)
588         pref_path = g_strconcat("fullscreen.", pref, NULL);
589     else
590         pref_path = g_strconcat("window.", pref, NULL);
592     gint ison = prefs_get_int_attribute_limited(pref_path, "state", 1, 0, 1);
594     g_signal_handlers_block_by_func(G_OBJECT(menuitem), (gpointer)(GCallback)checkitem_toggled, user_data);
595     gtk_check_menu_item_set_active(menuitem, ison);
596     g_signal_handlers_unblock_by_func(G_OBJECT(menuitem), (gpointer)(GCallback)checkitem_toggled, user_data);
598     return FALSE;
602 void
603 sp_ui_menu_append_check_item_from_verb(GtkMenu *menu, Inkscape::UI::View::View *view, gchar const *label, gchar const *tip, gchar const *pref,
604                                        void (*callback_toggle)(GtkCheckMenuItem *, gpointer user_data),
605                                        gboolean (*callback_update)(GtkWidget *widget, GdkEventExpose *event, gpointer user_data),
606                                        Inkscape::Verb *verb)
608     GtkWidget *item;
610     unsigned int shortcut = 0;
611     SPAction *action = NULL;
613     if (verb) {
614         shortcut = sp_shortcut_get_primary(verb);
615         action = verb->get_action(view);
616     }
618     if (verb && shortcut) {
619         gchar c[256];
620         sp_ui_shortcut_string(shortcut, c);
622         GtkWidget *hb = gtk_hbox_new(FALSE, 16);
624         {
625             GtkWidget *l = gtk_label_new_with_mnemonic(action ? action->name : label);
626             gtk_misc_set_alignment((GtkMisc *) l, 0.0, 0.5);
627             gtk_box_pack_start((GtkBox *) hb, l, TRUE, TRUE, 0);
628         }
630         {
631             GtkWidget *l = gtk_label_new(c);
632             gtk_misc_set_alignment((GtkMisc *) l, 1.0, 0.5);
633             gtk_box_pack_end((GtkBox *) hb, l, FALSE, FALSE, 0);
634         }
636         gtk_widget_show_all(hb);
638         item = gtk_check_menu_item_new();
639         gtk_container_add((GtkContainer *) item, hb);
640     } else {
641         GtkWidget *l = gtk_label_new_with_mnemonic(action ? action->name : label);
642         gtk_misc_set_alignment((GtkMisc *) l, 0.0, 0.5);
643         item = gtk_check_menu_item_new();
644         gtk_container_add((GtkContainer *) item, l);
645     }
646 #if 0
647     nr_active_object_add_listener((NRActiveObject *)action, (NRObjectEventVector *)&menu_item_event_vector, sizeof(SPActionEventVector), item);
648     if (!action->sensitive) {
649         gtk_widget_set_sensitive(item, FALSE);
650     }
651 #endif
652     gtk_widget_show(item);
654     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
656     g_object_set_data(G_OBJECT(item), "view", (gpointer) view);
658     g_signal_connect( G_OBJECT(item), "toggled", (GCallback) callback_toggle, (void *) pref);
659     g_signal_connect( G_OBJECT(item), "expose_event", (GCallback) callback_update, (void *) pref);
661     g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), (gpointer) (action ? action->tip : tip));
662     g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), NULL);
665 static void
666 sp_recent_open(GtkWidget *widget, gchar const *uri)
668     sp_file_open(uri, NULL);
671 static void
672 sp_file_new_from_template(GtkWidget *widget, gchar const *uri)
674     sp_file_new(uri);
677 void
678 sp_menu_append_new_templates(GtkWidget *menu, Inkscape::UI::View::View *view)
680     std::list<gchar *> sources;
681     sources.push_back( profile_path("templates") ); // first try user's local dir
682     sources.push_back( g_strdup(INKSCAPE_TEMPLATESDIR) ); // then the system templates dir
684     // Use this loop to iterate through a list of possible document locations.
685     while (!sources.empty()) {
686         gchar *dirname = sources.front();
688         if ( Inkscape::IO::file_test( dirname, (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR) ) ) {
689             GError *err = 0;
690             GDir *dir = g_dir_open(dirname, 0, &err);
692             if (dir) {
693                 for (gchar const *file = g_dir_read_name(dir); file != NULL; file = g_dir_read_name(dir)) {
694                     if (!g_str_has_suffix(file, ".svg") && !g_str_has_suffix(file, ".svgz"))
695                         continue; // skip non-svg files
697                     gchar *basename = g_path_get_basename(file);
698                     if (g_str_has_suffix(basename, ".svg") && g_str_has_prefix(basename, "default."))
699                         continue; // skip default.*.svg (i.e. default.svg and translations) - it's in the menu already
701                     gchar const *filepath = g_build_filename(dirname, file, NULL);
702                     gchar *dupfile = g_strndup(file, strlen(file) - 4);
703                     gchar *filename =  g_filename_to_utf8(dupfile,  -1, NULL, NULL, NULL);
704                     g_free(dupfile);
705                     GtkWidget *item = gtk_menu_item_new_with_label(filename);
706                     g_free(filename);
708                     gtk_widget_show(item);
709                     // how does "filepath" ever get freed?
710                     g_signal_connect(G_OBJECT(item),
711                                      "activate",
712                                      G_CALLBACK(sp_file_new_from_template),
713                                      (gpointer) filepath);
715                     if (view) {
716                         // set null tip for now; later use a description from the template file
717                         g_object_set_data(G_OBJECT(item), "view", (gpointer) view);
718                         g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), (gpointer) NULL );
719                         g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), NULL);
720                     }
722                     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
723                 }
724                 g_dir_close(dir);
725             }
726         }
728         // toss the dirname
729         g_free(dirname);
730         sources.pop_front();
731     }
734 void
735 sp_menu_append_recent_documents(GtkWidget *menu, Inkscape::UI::View::View* /* view */)
737     gchar const **recent = prefs_get_recent_files();
738     if (recent) {
739         int i;
741         for (i = 0; recent[i] != NULL; i += 2) {
742             gchar const *uri = recent[i];
743             gchar const *name = recent[i + 1];
745             GtkWidget *item = gtk_menu_item_new_with_label(name);
746             gtk_widget_show(item);
747             g_signal_connect(G_OBJECT(item),
748                              "activate",
749                              G_CALLBACK(sp_recent_open),
750                              (gpointer)uri);
751             gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
752         }
754         g_free(recent);
755     } else {
756         GtkWidget *item = gtk_menu_item_new_with_label(_("None"));
757         gtk_widget_show(item);
758         gtk_widget_set_sensitive(item, FALSE);
759         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
760     }
763 void
764 sp_ui_checkboxes_menus(GtkMenu *m, Inkscape::UI::View::View *view)
766     //sp_ui_menu_append_check_item_from_verb(m, view, _("_Menu"), _("Show or hide the menu bar"), "menu",
767     //                                       checkitem_toggled, checkitem_update, 0);
768     sp_ui_menu_append_check_item_from_verb(m, view, _("Commands Bar"), _("Show or hide the Commands bar (under the menu)"), "commands",
769                                            checkitem_toggled, checkitem_update, 0);
770     sp_ui_menu_append_check_item_from_verb(m, view, _("Tool Controls Bar"), _("Show or hide the Tool Controls bar"), "toppanel",
771                                            checkitem_toggled, checkitem_update, 0);
772     sp_ui_menu_append_check_item_from_verb(m, view, _("_Toolbox"), _("Show or hide the main toolbox (on the left)"), "toolbox",
773                                            checkitem_toggled, checkitem_update, 0);
774     sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "rulers",
775                                            checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_RULERS));
776     sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "scrollbars",
777                                            checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_SCROLLBARS));
778     sp_ui_menu_append_check_item_from_verb(m, view, _("_Palette"), _("Show or hide the color palette"), "panels",
779                                            checkitem_toggled, checkitem_update, 0);
780     sp_ui_menu_append_check_item_from_verb(m, view, _("_Statusbar"), _("Show or hide the statusbar (at the bottom of the window)"), "statusbar",
781                                            checkitem_toggled, checkitem_update, 0);
784 /** \brief  This function turns XML into a menu
785     \param  menus  This is the XML that defines the menu
786     \param  menu   Menu to be added to
787     \param  view   The View that this menu is being built for
789     This function is realitively simple as it just goes through the XML
790     and parses the individual elements.  In the case of a submenu, it
791     just calls itself recursively.  Because it is only reasonable to have
792     a couple of submenus, it is unlikely this will go more than two or
793     three times.
795     In the case of an unreconginzed verb, a menu item is made to identify
796     the verb that is missing, and display that.  The menu item is also made
797     insensitive.
798 */
799 void
800 sp_ui_build_dyn_menus(Inkscape::XML::Node *menus, GtkWidget *menu, Inkscape::UI::View::View *view)
802     if (menus == NULL) return;
803     if (menu == NULL)  return;
804     GSList *group = NULL;
806     for (Inkscape::XML::Node *menu_pntr = menus;
807          menu_pntr != NULL;
808          menu_pntr = menu_pntr->next()) {
809         if (!strcmp(menu_pntr->name(), "submenu")) {
810             GtkWidget *mitem = gtk_menu_item_new_with_mnemonic(_(menu_pntr->attribute("name")));
811             GtkWidget *submenu = gtk_menu_new();
812             sp_ui_build_dyn_menus(menu_pntr->firstChild(), submenu, view);
813             gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), GTK_WIDGET(submenu));
814             gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
815             continue;
816         }
817         if (!strcmp(menu_pntr->name(), "verb")) {
818             gchar const *verb_name = menu_pntr->attribute("verb-id");
819             Inkscape::Verb *verb = Inkscape::Verb::getbyid(verb_name);
821             if (verb != NULL) {
822                 if (menu_pntr->attribute("radio") != NULL) {
823                     GtkWidget *item = sp_ui_menu_append_item_from_verb (GTK_MENU(menu), verb, view, true, group);
824                     group = gtk_radio_menu_item_get_group( GTK_RADIO_MENU_ITEM(item));
825                     if (menu_pntr->attribute("default") != NULL) {
826                         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
827                     }
828                 } else {
829                     sp_ui_menu_append_item_from_verb(GTK_MENU(menu), verb, view);
830                     group = NULL;
831                 }
832             } else {
833                 gchar string[120];
834                 g_snprintf(string, 120, _("Verb \"%s\" Unknown"), verb_name);
835                 string[119] = '\0'; /* may not be terminated */
836                 GtkWidget *item = gtk_menu_item_new_with_label(string);
837                 gtk_widget_set_sensitive(item, false);
838                 gtk_widget_show(item);
839                 gtk_menu_append(GTK_MENU(menu), item);
840             }
841             continue;
842         }
843         if (!strcmp(menu_pntr->name(), "separator")
844                 // This was spelt wrong in the original version
845                 // and so this is for backward compatibility.  It can
846                 // probably be dropped after the 0.44 release.
847              || !strcmp(menu_pntr->name(), "seperator")) {
848             GtkWidget *item = gtk_separator_menu_item_new();
849             gtk_widget_show(item);
850             gtk_menu_append(GTK_MENU(menu), item);
851             continue;
852         }
853         if (!strcmp(menu_pntr->name(), "template-list")) {
854             sp_menu_append_new_templates(menu, view);
855             continue;
856         }
857         if (!strcmp(menu_pntr->name(), "recent-file-list")) {
858             sp_menu_append_recent_documents(menu, view);
859             continue;
860         }
861         if (!strcmp(menu_pntr->name(), "objects-checkboxes")) {
862             sp_ui_checkboxes_menus(GTK_MENU(menu), view);
863             continue;
864         }
865     }
868 /** \brief  Build the main tool bar
869     \param  view  View to build the bar for
871     Currently the main tool bar is built as a dynamic XML menu using
872     \c sp_ui_build_dyn_menus.  This function builds the bar, and then
873     pass it to get items attached to it.
874 */
875 GtkWidget *
876 sp_ui_main_menubar(Inkscape::UI::View::View *view)
878     GtkWidget *mbar = gtk_menu_bar_new();
880     sp_ui_build_dyn_menus(inkscape_get_menus(INKSCAPE), mbar, view);
882     return mbar;
885 static void leave_group(GtkMenuItem *, SPDesktop *desktop) {
886     desktop->setCurrentLayer(SP_OBJECT_PARENT(desktop->currentLayer()));
889 static void enter_group(GtkMenuItem *mi, SPDesktop *desktop) {
890     desktop->setCurrentLayer(reinterpret_cast<SPObject *>(g_object_get_data(G_OBJECT(mi), "group")));
891     sp_desktop_selection(desktop)->clear();
894 GtkWidget *
895 sp_ui_context_menu(Inkscape::UI::View::View *view, SPItem *item)
897     GtkWidget *m;
898     SPDesktop *dt;
900     dt = static_cast<SPDesktop*>(view);
902     m = gtk_menu_new();
904     /* Undo and Redo */
905     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_UNDO), view);
906     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_REDO), view);
908     /* Separator */
909     sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
911     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_CUT), view);
912     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_COPY), view);
913     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_PASTE), view);
915     /* Separator */
916     sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
918     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_DUPLICATE), view);
919     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_DELETE), view);
921     /* Item menu */
922     if (item) {
923         sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
924         sp_object_menu((SPObject *) item, dt, GTK_MENU(m));
925     }
927     /* layer menu */
928     SPGroup *group=NULL;
929     if (item) {
930         if (SP_IS_GROUP(item)) {
931             group = SP_GROUP(item);
932         } else if ( item != dt->currentRoot() && SP_IS_GROUP(SP_OBJECT_PARENT(item)) ) {
933             group = SP_GROUP(SP_OBJECT_PARENT(item));
934         }
935     }
937     if (( group && group != dt->currentLayer() ) ||
938         ( dt->currentLayer() != dt->currentRoot() ) ) {
939         sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
940     }
942     if ( group && group != dt->currentLayer() ) {
943         /* TRANSLATORS: #%s is the id of the group e.g. <g id="#g7">, not a number. */
944         gchar *label=g_strdup_printf(_("Enter group #%s"), SP_OBJECT_ID(group));
945         GtkWidget *w = gtk_menu_item_new_with_label(label);
946         g_free(label);
947         g_object_set_data(G_OBJECT(w), "group", group);
948         g_signal_connect(G_OBJECT(w), "activate", GCallback(enter_group), dt);
949         gtk_widget_show(w);
950         gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
951     }
953     if ( dt->currentLayer() != dt->currentRoot() ) {
954         if ( SP_OBJECT_PARENT(dt->currentLayer()) != dt->currentRoot() ) {
955             GtkWidget *w = gtk_menu_item_new_with_label(_("Go to parent"));
956             g_signal_connect(G_OBJECT(w), "activate", GCallback(leave_group), dt);
957             gtk_widget_show(w);
958             gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
960         }
961     }
963     return m;
966 /* Drag and Drop */
967 void
968 sp_ui_drag_data_received(GtkWidget *widget,
969                          GdkDragContext *drag_context,
970                          gint x, gint y,
971                          GtkSelectionData *data,
972                          guint info,
973                          guint event_time,
974                          gpointer user_data)
976     switch (info) {
977 #if ENABLE_MAGIC_COLORS
978         case APP_X_INKY_COLOR:
979         {
980             SPDesktop *desktop = SP_ACTIVE_DESKTOP;
981             int destX = 0;
982             int destY = 0;
983             gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
984             NR::Point where( sp_canvas_window_to_world( desktop->canvas, NR::Point( destX, destY ) ) );
986             SPItem *item = desktop->item_at_point( where, true );
987             if ( item )
988             {
989                 if ( data->length >= 8 ) {
990                     cmsHPROFILE srgbProf = cmsCreate_sRGBProfile();
992                     gchar c[64] = {0};
993                     // Careful about endian issues.
994                     guint16* dataVals = (guint16*)data->data;
995                     sp_svg_write_color( c, 64,
996                                         SP_RGBA32_U_COMPOSE(
997                                             0x0ff & (dataVals[0] >> 8),
998                                             0x0ff & (dataVals[1] >> 8),
999                                             0x0ff & (dataVals[2] >> 8),
1000                                             0xff // can't have transparency in the color itself
1001                                             //0x0ff & (data->data[3] >> 8),
1002                                             ));
1003                     SPCSSAttr *css = sp_repr_css_attr_new();
1004                     bool updatePerformed = false;
1006                     if ( data->length > 14 ) {
1007                         int flags = dataVals[4];
1009                         // piggie-backed palette entry info
1010                         int index = dataVals[5];
1011                         Glib::ustring palName;
1012                         for ( int i = 0; i < dataVals[6]; i++ ) {
1013                             palName += (gunichar)dataVals[7+i];
1014                         }
1016                         // Now hook in a magic tag of some sort.
1017                         if ( !palName.empty() && (flags & 1) ) {
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) ? "inkscape:x-fill-tag":"inkscape:x-stroke-tag",
1025                                                     palName.c_str(),
1026                                                     false );
1027                             item->updateRepr();
1029                             sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
1030                             updatePerformed = true;
1031                         }
1032                     }
1034                     if ( !updatePerformed ) {
1035                         sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
1036                     }
1038                     sp_desktop_apply_css_recursive( item, css, true );
1039                     item->updateRepr();
1041                     SPDocument *doc = SP_ACTIVE_DOCUMENT;
1042                     sp_document_done( doc , SP_VERB_NONE, 
1043                                       _("Drop color"));
1045                     if ( srgbProf ) {
1046                         cmsCloseProfile( srgbProf );
1047                     }
1048                 }
1049             }
1050         }
1051         break;
1052 #endif // ENABLE_MAGIC_COLORS
1054         case APP_X_COLOR:
1055         {
1056             SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1057             int destX = 0;
1058             int destY = 0;
1059             gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
1060             NR::Point where( sp_canvas_window_to_world( desktop->canvas, NR::Point( destX, destY ) ) );
1062             SPItem *item = desktop->item_at_point( where, true );
1063             if ( item )
1064             {
1065                 if ( data->length == 8 ) {
1066                     gchar c[64] = {0};
1067                     // Careful about endian issues.
1068                     guint16* dataVals = (guint16*)data->data;
1069                     sp_svg_write_color( c, 64,
1070                                         SP_RGBA32_U_COMPOSE(
1071                                             0x0ff & (dataVals[0] >> 8),
1072                                             0x0ff & (dataVals[1] >> 8),
1073                                             0x0ff & (dataVals[2] >> 8),
1074                                             0xff // can't have transparency in the color itself
1075                                             //0x0ff & (data->data[3] >> 8),
1076                                             ));
1077                     SPCSSAttr *css = sp_repr_css_attr_new();
1078                     sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
1080                     sp_desktop_apply_css_recursive( item, css, true );
1081                     item->updateRepr();
1083                     SPDocument *doc = SP_ACTIVE_DOCUMENT;
1084                     sp_document_done( doc , SP_VERB_NONE, 
1085                                       _("Drop color"));
1086                 }
1087             }
1088         }
1089         break;
1091         case SVG_DATA:
1092         case SVG_XML_DATA: {
1093             gchar *svgdata = (gchar *)data->data;
1095             SPDocument *doc = SP_ACTIVE_DOCUMENT;
1097             Inkscape::XML::Document *rnewdoc = sp_repr_read_mem(svgdata, data->length, SP_SVG_NS_URI);
1099             if (rnewdoc == NULL) {
1100                 sp_ui_error_dialog(_("Could not parse SVG data"));
1101                 return;
1102             }
1104             Inkscape::XML::Node *repr = sp_repr_document_root(rnewdoc);
1105             gchar const *style = repr->attribute("style");
1107             Inkscape::XML::Node *newgroup = sp_repr_new("svg:g");
1108             newgroup->setAttribute("style", style);
1110             for (Inkscape::XML::Node *child = repr->firstChild(); child != NULL; child = child->next()) {
1111                 Inkscape::XML::Node *newchild = child->duplicate();
1112                 newgroup->appendChild(newchild);
1113             }
1115             Inkscape::GC::release(rnewdoc);
1117             SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1118             // Add it to the current layer
1120             // Greg's edits to add intelligent positioning of svg drops
1121             SPObject *new_obj = NULL;
1122             new_obj = desktop->currentLayer()->appendChildRepr(newgroup);
1124             Inkscape::Selection *selection = sp_desktop_selection(desktop);
1125             selection->set(SP_ITEM(new_obj));
1126             // To move the imported object, we must temporarily set the "transform pattern with
1127             // object" option.
1128             {
1129                 int const saved_pref = prefs_get_int_attribute("options.transform", "pattern", 1);
1130                 prefs_set_int_attribute("options.transform", "pattern", 1);
1131                 sp_document_ensure_up_to_date(sp_desktop_document(desktop));
1132                 NR::Point m( desktop->point() - selection->bounds().midpoint() );
1133                 sp_selection_move_relative(selection, m);
1134                 prefs_set_int_attribute("options.transform", "pattern", saved_pref);
1135             }
1137             Inkscape::GC::release(newgroup);
1138             sp_document_done(doc, SP_VERB_NONE, 
1139                              _("Drop SVG"));
1140             break;
1141         }
1143         case URI_LIST: {
1144             gchar *uri = (gchar *)data->data;
1145             sp_ui_import_files(uri);
1146             break;
1147         }
1149         case PNG_DATA:
1150         case JPEG_DATA:
1151         case IMAGE_DATA: {
1152             char tmp[1024];
1154             StringOutputStream outs;
1155             Base64OutputStream b64out(outs);
1156             b64out.setColumnWidth(0);
1158             SPDocument *doc = SP_ACTIVE_DOCUMENT;
1160             Inkscape::XML::Node *newImage = sp_repr_new("svg:image");
1162             for ( int i = 0; i < data->length; i++ ) {
1163                 b64out.put( data->data[i] );
1164             }
1165             b64out.close();
1168             Glib::ustring str = outs.getString();
1170             snprintf( tmp, sizeof(tmp), "data:%s;base64,", gdk_atom_name(data->type) );
1171             str.insert( 0, tmp );
1172             newImage->setAttribute("xlink:href", str.c_str());
1174             GError *error = NULL;
1175             GdkPixbufLoader *loader = gdk_pixbuf_loader_new_with_mime_type( gdk_atom_name(data->type), &error );
1176             if ( loader ) {
1177                 error = NULL;
1178                 if ( gdk_pixbuf_loader_write( loader, data->data, data->length, &error) ) {
1179                     GdkPixbuf *pbuf = gdk_pixbuf_loader_get_pixbuf(loader);
1180                     if ( pbuf ) {
1181                         int width = gdk_pixbuf_get_width(pbuf);
1182                         int height = gdk_pixbuf_get_height(pbuf);
1183                         snprintf( tmp, sizeof(tmp), "%d", width );
1184                         newImage->setAttribute("width", tmp);
1186                         snprintf( tmp, sizeof(tmp), "%d", height );
1187                         newImage->setAttribute("height", tmp);
1188                     }
1189                 }
1190             }
1192             SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1194             // Add it to the current layer
1195             desktop->currentLayer()->appendChildRepr(newImage);
1197             Inkscape::GC::release(newImage);
1198             sp_document_done( doc , SP_VERB_NONE, 
1199                               _("Drop bitmap image"));
1200             break;
1201         }
1202     }
1205 static void
1206 sp_ui_import_files(gchar *buffer)
1208     GList *list = gnome_uri_list_extract_filenames(buffer);
1209     if (!list)
1210         return;
1211     g_list_foreach(list, sp_ui_import_one_file_with_check, NULL);
1212     g_list_foreach(list, (GFunc) g_free, NULL);
1213     g_list_free(list);
1216 static void
1217 sp_ui_import_one_file_with_check(gpointer filename, gpointer unused)
1219     if (filename) {
1220         if (strlen((char const *)filename) > 2)
1221             sp_ui_import_one_file((char const *)filename);
1222     }
1225 static void
1226 sp_ui_import_one_file(char const *filename)
1228     SPDocument *doc = SP_ACTIVE_DOCUMENT;
1229     if (!doc) return;
1231     if (filename == NULL) return;
1233     // Pass off to common implementation
1234     // TODO might need to get the proper type of Inkscape::Extension::Extension
1235     file_import( doc, filename, NULL );
1238 void
1239 sp_ui_error_dialog(gchar const *message)
1241     GtkWidget *dlg;
1242     gchar *safeMsg = Inkscape::IO::sanitizeString(message);
1244     dlg = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
1245                                  GTK_BUTTONS_CLOSE, safeMsg);
1246     sp_transientize(dlg);
1247     gtk_window_set_resizable(GTK_WINDOW(dlg), FALSE);
1248     gtk_dialog_run(GTK_DIALOG(dlg));
1249     gtk_widget_destroy(dlg);
1250     g_free(safeMsg);
1253 bool
1254 sp_ui_overwrite_file(gchar const *filename)
1256     bool return_value = FALSE;
1257     GtkWidget *dialog;
1258     GtkWidget *hbox;
1259     GtkWidget *boxdata;
1260     gchar *title;
1261     gchar *text;
1263     if (Inkscape::IO::file_test(filename, G_FILE_TEST_EXISTS)) {
1265         title = g_strdup_printf(_("Overwrite %s"), filename);
1266         dialog = gtk_dialog_new_with_buttons(title,
1267                                              NULL,
1268                                              (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
1269                                              GTK_STOCK_NO,
1270                                              GTK_RESPONSE_NO,
1271                                              GTK_STOCK_YES,
1272                                              GTK_RESPONSE_YES,
1273                                              NULL);
1274         gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_YES);
1276         sp_transientize(dialog);
1277         gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
1279         hbox = gtk_hbox_new(FALSE, 5);
1281         // TODO - replace with Inkscape-specific call
1282         boxdata = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
1284         gtk_widget_show(boxdata);
1285         gtk_box_pack_start(GTK_BOX(hbox), boxdata, TRUE, TRUE, 5);
1286         text = g_strdup_printf(_("The file %s already exists.  Do you want to overwrite that file with the current document?"), filename);
1287         boxdata = gtk_label_new(text);
1288         gtk_label_set_line_wrap(GTK_LABEL(boxdata), TRUE);
1289         gtk_widget_show(boxdata);
1290         gtk_box_pack_start(GTK_BOX(hbox), boxdata, FALSE, FALSE, 5);
1291         gtk_widget_show(hbox);
1292         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, TRUE, TRUE, 5);
1294         if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES) {
1295             return_value = TRUE;
1296         } else {
1297             return_value = FALSE;
1298         }
1300         gtk_widget_destroy(dialog);
1301         g_free(title);
1302         g_free(text);
1303     } else {
1304         return_value = TRUE;
1305     }
1307     return return_value;
1310 static void
1311 sp_ui_menu_item_set_sensitive(SPAction *action, unsigned int sensitive, void *data)
1313     return gtk_widget_set_sensitive(GTK_WIDGET(data), sensitive);
1316 static void
1317 sp_ui_menu_item_set_name(SPAction *action, Glib::ustring name, void *data)
1319     gtk_label_set_markup_with_mnemonic(
1320         GTK_LABEL (gtk_container_get_children(GTK_CONTAINER (GTK_BIN (data)->child))->data), 
1321         name.c_str());
1325 /*
1326   Local Variables:
1327   mode:c++
1328   c-file-style:"stroustrup"
1329   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1330   indent-tabs-mode:nil
1331   fill-column:99
1332   End:
1333 */
1334 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :