cleanup various merge conflict resolution errors/omissions
[ardour.git] / gtk2_ardour / utils.cc
1 /*
2     Copyright (C) 2003 Paul Davis
3
4     This program is free software; you an redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
23
24 #include <cstdlib>
25 #include <clocale>
26 #include <cstring>
27 #include <cctype>
28 #include <cmath>
29 #include <list>
30 #include <sys/stat.h>
31 #include <gtkmm/rc.h>
32 #include <gtkmm/window.h>
33 #include <gtkmm/combo.h>
34 #include <gtkmm/label.h>
35 #include <gtkmm/paned.h>
36 #include <gtk/gtkpaned.h>
37 #include <boost/algorithm/string.hpp>
38
39 #include "pbd/file_utils.h"
40
41 #include <gtkmm2ext/utils.h>
42
43 #include "ardour/filesystem_paths.h"
44
45 #include "canvas/item.h"
46 #include "canvas/utils.h"
47
48 #include "debug.h"
49 #include "public_editor.h"
50 #include "keyboard.h"
51 #include "utils.h"
52 #include "i18n.h"
53 #include "rgb_macros.h"
54 #include "gui_thread.h"
55 #include "ui_config.h"
56 #include "ardour_dialog.h"
57 #include "ardour_ui.h"
58
59 using namespace std;
60 using namespace Gtk;
61 using namespace Glib;
62 using namespace PBD;
63 using Gtkmm2ext::Keyboard;
64
65 namespace ARDOUR_UI_UTILS {
66         sigc::signal<void>  DPIReset;
67 }
68
69 #ifdef PLATFORM_WINDOWS
70 #define random() rand()
71 #endif
72
73
74 /** Add an element to a menu, settings its sensitivity.
75  * @param m Menu to add to.
76  * @param e Element to add.
77  * @param s true to make sensitive, false to make insensitive
78  */
79 void
80 ARDOUR_UI_UTILS::add_item_with_sensitivity (Menu_Helpers::MenuList& m, Menu_Helpers::MenuElem e, bool s)
81 {
82         m.push_back (e);
83         if (!s) {
84                 m.back().set_sensitive (false);
85         }
86 }
87
88
89 gint
90 ARDOUR_UI_UTILS::just_hide_it (GdkEventAny */*ev*/, Gtk::Window *win)
91 {
92         win->hide ();
93         return 0;
94 }
95
96 /* xpm2rgb copied from nixieclock, which bore the legend:
97
98     nixieclock - a nixie desktop timepiece
99     Copyright (C) 2000 Greg Ercolano, erco@3dsite.com
100
101     and was released under the GPL.
102 */
103
104 unsigned char*
105 ARDOUR_UI_UTILS::xpm2rgb (const char** xpm, uint32_t& w, uint32_t& h)
106 {
107         static long vals[256], val;
108         uint32_t t, x, y, colors, cpp;
109         unsigned char c;
110         unsigned char *savergb, *rgb;
111
112         // PARSE HEADER
113
114         if ( sscanf(xpm[0], "%u%u%u%u", &w, &h, &colors, &cpp) != 4 ) {
115                 error << string_compose (_("bad XPM header %1"), xpm[0])
116                       << endmsg;
117                 return 0;
118         }
119
120         savergb = rgb = (unsigned char*) malloc (h * w * 3);
121
122         // LOAD XPM COLORMAP LONG ENOUGH TO DO CONVERSION
123         for (t = 0; t < colors; ++t) {
124                 sscanf (xpm[t+1], "%c c #%lx", &c, &val);
125                 vals[c] = val;
126         }
127
128         // COLORMAP -> RGB CONVERSION
129         //    Get low 3 bytes from vals[]
130         //
131
132         const char *p;
133         for (y = h-1; y > 0; --y) {
134
135                 for (p = xpm[1+colors+(h-y-1)], x = 0; x < w; x++, rgb += 3) {
136                         val = vals[(int)*p++];
137                         *(rgb+2) = val & 0xff; val >>= 8;  // 2:B
138                         *(rgb+1) = val & 0xff; val >>= 8;  // 1:G
139                         *(rgb+0) = val & 0xff;             // 0:R
140                 }
141         }
142
143         return (savergb);
144 }
145
146 unsigned char*
147 ARDOUR_UI_UTILS::xpm2rgba (const char** xpm, uint32_t& w, uint32_t& h)
148 {
149         static long vals[256], val;
150         uint32_t t, x, y, colors, cpp;
151         unsigned char c;
152         unsigned char *savergb, *rgb;
153         char transparent;
154
155         // PARSE HEADER
156
157         if ( sscanf(xpm[0], "%u%u%u%u", &w, &h, &colors, &cpp) != 4 ) {
158                 error << string_compose (_("bad XPM header %1"), xpm[0])
159                       << endmsg;
160                 return 0;
161         }
162
163         savergb = rgb = (unsigned char*) malloc (h * w * 4);
164
165         // LOAD XPM COLORMAP LONG ENOUGH TO DO CONVERSION
166
167         if (strstr (xpm[1], "None")) {
168                 sscanf (xpm[1], "%c", &transparent);
169                 t = 1;
170         } else {
171                 transparent = 0;
172                 t = 0;
173         }
174
175         for (; t < colors; ++t) {
176                 sscanf (xpm[t+1], "%c c #%lx", &c, &val);
177                 vals[c] = val;
178         }
179
180         // COLORMAP -> RGB CONVERSION
181         //    Get low 3 bytes from vals[]
182         //
183
184         const char *p;
185         for (y = h-1; y > 0; --y) {
186
187                 char alpha;
188
189                 for (p = xpm[1+colors+(h-y-1)], x = 0; x < w; x++, rgb += 4) {
190
191                         if (transparent && (*p++ == transparent)) {
192                                 alpha = 0;
193                                 val = 0;
194                         } else {
195                                 alpha = 255;
196                                 val = vals[(int)*p];
197                         }
198
199                         *(rgb+3) = alpha;                  // 3: alpha
200                         *(rgb+2) = val & 0xff; val >>= 8;  // 2:B
201                         *(rgb+1) = val & 0xff; val >>= 8;  // 1:G
202                         *(rgb+0) = val & 0xff;             // 0:R
203                 }
204         }
205
206         return (savergb);
207 }
208
209 /** Returns a Pango::FontDescription given a string describing the font.
210  *
211  * If the returned FontDescription does not specify a family, then
212  * the family is set to "Sans". This mirrors GTK's behaviour in
213  * gtkstyle.c.
214  *
215  * Some environments will force Pango to specify the family
216  * even if it was not specified in the string describing the font.
217  * Such environments should be left unaffected by this function,
218  * since the font family will be left alone.
219  *
220  * There may be other similar font specification enforcement
221  * that we might add here later.
222  */
223 Pango::FontDescription
224 ARDOUR_UI_UTILS::sanitized_font (std::string const& name)
225 {
226         Pango::FontDescription fd (name);
227
228         if (fd.get_family().empty()) {
229                 fd.set_family ("Sans");
230         }
231
232         return fd;
233 }
234
235 Pango::FontDescription
236 ARDOUR_UI_UTILS::get_font_for_style (string widgetname)
237 {
238         Gtk::Window window (WINDOW_TOPLEVEL);
239         Gtk::Label foobar;
240         Glib::RefPtr<Gtk::Style> style;
241
242         window.add (foobar);
243         foobar.set_name (widgetname);
244         foobar.ensure_style();
245
246         style = foobar.get_style ();
247
248         Glib::RefPtr<const Pango::Layout> layout = foobar.get_layout();
249
250         PangoFontDescription *pfd = const_cast<PangoFontDescription *> (pango_layout_get_font_description(const_cast<PangoLayout *>(layout->gobj())));
251
252         if (!pfd) {
253
254                 /* layout inherited its font description from a PangoContext */
255
256                 PangoContext* ctxt = (PangoContext*) pango_layout_get_context (const_cast<PangoLayout*>(layout->gobj()));
257                 pfd =  pango_context_get_font_description (ctxt);
258                 return Pango::FontDescription (pfd); /* make a copy */
259         }
260
261         return Pango::FontDescription (pfd); /* make a copy */
262 }
263
264 void
265 ARDOUR_UI_UTILS::set_color_from_rgb (Gdk::Color& c, uint32_t rgb)
266 {
267         /* Gdk::Color color ranges are 16 bit, so scale from 8 bit by
268            multiplying by 256.
269         */
270         c.set_rgb ((rgb >> 16)*256, ((rgb & 0xff00) >> 8)*256, (rgb & 0xff)*256);
271 }
272
273 void
274 ARDOUR_UI_UTILS::set_color_from_rgba (Gdk::Color& c, uint32_t rgba)
275 {
276         /* Gdk::Color color ranges are 16 bit, so scale from 8 bit by
277            multiplying by 256.
278         */
279         c.set_rgb ((rgba >> 24)*256, ((rgba & 0xff0000) >> 16)*256, ((rgba & 0xff00) >> 8)*256);
280 }
281
282 uint32_t
283 ARDOUR_UI_UTILS::gdk_color_to_rgba (Gdk::Color const& c)
284 {
285         /* since alpha value is not available from a Gdk::Color, it is
286            hardcoded as 0xff (aka 255 or 1.0)
287         */
288
289         const uint32_t r = c.get_red_p () * 255.0;
290         const uint32_t g = c.get_green_p () * 255.0;
291         const uint32_t b = c.get_blue_p () * 255.0;
292         const uint32_t a = 0xff;
293
294         return RGBA_TO_UINT (r,g,b,a);
295 }
296
297
298 bool
299 ARDOUR_UI_UTILS::relay_key_press (GdkEventKey* ev, Gtk::Window* win)
300 {
301         return ARDOUR_UI::instance()->key_event_handler (ev, win);
302 }
303
304 bool
305 ARDOUR_UI_UTILS::emulate_key_event (unsigned int keyval)
306 {
307         GdkDisplay  *display = gtk_widget_get_display (GTK_WIDGET(ARDOUR_UI::instance()->main_window().gobj()));
308         GdkKeymap   *keymap  = gdk_keymap_get_for_display (display);
309         GdkKeymapKey *keymapkey = NULL;
310         gint n_keys;
311         
312         if (!gdk_keymap_get_entries_for_keyval(keymap, keyval, &keymapkey, &n_keys)) return false;
313         if (n_keys !=1) { g_free(keymapkey); return false;}
314
315         Gtk::Window& main_window (ARDOUR_UI::instance()->main_window());
316         
317         GdkEventKey ev;
318         ev.type = GDK_KEY_PRESS;
319         ev.window = main_window.get_window()->gobj();
320         ev.send_event = FALSE;
321         ev.time = 0;
322         ev.state = 0;
323         ev.keyval = keyval;
324         ev.length = 0;
325         ev.string = const_cast<gchar*> ("");
326         ev.hardware_keycode = keymapkey[0].keycode;
327         ev.group = keymapkey[0].group;
328         g_free(keymapkey);
329
330         relay_key_press (&ev, &main_window);
331         ev.type = GDK_KEY_RELEASE;
332         return relay_key_press(&ev, &main_window);
333 }
334
335 string
336 ARDOUR_UI_UTILS::show_gdk_event_state (int state)
337 {
338         string s;
339         if (state & GDK_SHIFT_MASK) {
340                 s += "+SHIFT";
341         }
342         if (state & GDK_LOCK_MASK) {
343                 s += "+LOCK";
344         }
345         if (state & GDK_CONTROL_MASK) {
346                 s += "+CONTROL";
347         }
348         if (state & GDK_MOD1_MASK) {
349                 s += "+MOD1";
350         }
351         if (state & GDK_MOD2_MASK) {
352                 s += "+MOD2";
353         }
354         if (state & GDK_MOD3_MASK) {
355                 s += "+MOD3";
356         }
357         if (state & GDK_MOD4_MASK) {
358                 s += "+MOD4";
359         }
360         if (state & GDK_MOD5_MASK) {
361                 s += "+MOD5";
362         }
363         if (state & GDK_BUTTON1_MASK) {
364                 s += "+BUTTON1";
365         }
366         if (state & GDK_BUTTON2_MASK) {
367                 s += "+BUTTON2";
368         }
369         if (state & GDK_BUTTON3_MASK) {
370                 s += "+BUTTON3";
371         }
372         if (state & GDK_BUTTON4_MASK) {
373                 s += "+BUTTON4";
374         }
375         if (state & GDK_BUTTON5_MASK) {
376                 s += "+BUTTON5";
377         }
378         if (state & GDK_SUPER_MASK) {
379                 s += "+SUPER";
380         }
381         if (state & GDK_HYPER_MASK) {
382                 s += "+HYPER";
383         }
384         if (state & GDK_META_MASK) {
385                 s += "+META";
386         }
387         if (state & GDK_RELEASE_MASK) {
388                 s += "+RELEASE";
389         }
390
391         return s;
392 }
393
394 Glib::RefPtr<Gdk::Pixbuf>
395 ARDOUR_UI_UTILS::get_xpm (std::string name)
396 {
397         if (!xpm_map[name]) {
398
399                 Searchpath spath(ARDOUR::ardour_data_search_path());
400
401                 spath.add_subdirectory_to_paths("pixmaps");
402
403                 std::string data_file_path;
404
405                 if(!find_file (spath, name, data_file_path)) {
406                         fatal << string_compose (_("cannot find XPM file for %1"), name) << endmsg;
407                 }
408
409                 try {
410                         xpm_map[name] =  Gdk::Pixbuf::create_from_file (data_file_path);
411                 } catch(const Glib::Error& e)   {
412                         warning << "Caught Glib::Error: " << e.what() << endmsg;
413                 }
414         }
415
416         return xpm_map[name];
417 }
418
419 vector<string>
420 ARDOUR_UI_UTILS::get_icon_sets ()
421 {
422         Searchpath spath(ARDOUR::ardour_data_search_path());
423         spath.add_subdirectory_to_paths ("icons");
424         vector<string> r;
425
426         r.push_back (_("default"));
427
428         for (vector<string>::iterator s = spath.begin(); s != spath.end(); ++s) {
429
430                 vector<string> entries;
431
432                 get_paths (entries, *s, false, false);
433
434                 for (vector<string>::iterator e = entries.begin(); e != entries.end(); ++e) {
435                         if (Glib::file_test (*e, Glib::FILE_TEST_IS_DIR)) {
436                                 r.push_back (Glib::filename_to_utf8 (Glib::path_get_basename(*e)));
437                         }
438                 }
439         }
440
441         return r;
442 }
443
444 std::string
445 ARDOUR_UI_UTILS::get_icon_path (const char* cname, string icon_set, bool is_image)
446 {
447         std::string data_file_path;
448         string name = cname;
449
450         if (is_image) {
451                 name += X_(".png");
452         }
453
454         Searchpath spath(ARDOUR::ardour_data_search_path());
455
456         if (!icon_set.empty() && icon_set != _("default")) {
457
458                 /* add "icons/icon_set" but .. not allowed to add both of these at once */
459                 spath.add_subdirectory_to_paths ("icons");
460                 spath.add_subdirectory_to_paths (icon_set);
461
462                 find_file (spath, name, data_file_path);
463         } else {
464                 spath.add_subdirectory_to_paths ("icons");
465                 find_file (spath, name, data_file_path);
466         }
467
468         if (is_image && data_file_path.empty()) {
469
470                 if (!icon_set.empty() && icon_set != _("default")) {
471                         warning << string_compose (_("icon \"%1\" not found for icon set \"%2\", fallback to default"), cname, icon_set) << endmsg;
472                 }
473
474                 Searchpath def (ARDOUR::ardour_data_search_path());
475                 def.add_subdirectory_to_paths ("icons");
476
477                 if (!find_file (def, name, data_file_path)) {
478                         fatal << string_compose (_("cannot find icon image for %1 using %2"), name, spath.to_string()) << endmsg;
479                         abort(); /*NOTREACHED*/
480                 }
481         }
482
483         return data_file_path;
484 }
485
486 Glib::RefPtr<Gdk::Pixbuf>
487 ARDOUR_UI_UTILS::get_icon (const char* cname, string icon_set)
488 {
489         Glib::RefPtr<Gdk::Pixbuf> img;
490         try {
491                 img = Gdk::Pixbuf::create_from_file (get_icon_path (cname, icon_set));
492         } catch (const Gdk::PixbufError &e) {
493                 cerr << "Caught PixbufError: " << e.what() << endl;
494         } catch (...) {
495                 error << string_compose (_("Caught exception while loading icon named %1"), cname) << endmsg;
496         }
497
498         return img;
499 }
500
501 namespace ARDOUR_UI_UTILS {
502 Glib::RefPtr<Gdk::Pixbuf>
503 get_icon (const char* cname)
504 {
505         Glib::RefPtr<Gdk::Pixbuf> img;
506         try {
507                 img = Gdk::Pixbuf::create_from_file (get_icon_path (cname));
508         } catch (const Gdk::PixbufError &e) {
509                 cerr << "Caught PixbufError: " << e.what() << endl;
510         } catch (...) {
511                 error << string_compose (_("Caught exception while loading icon named %1"), cname) << endmsg;
512         }
513
514         return img;
515 }
516 }
517
518 string
519 ARDOUR_UI_UTILS::longest (vector<string>& strings)
520 {
521         if (strings.empty()) {
522                 return string ("");
523         }
524
525         vector<string>::iterator longest = strings.begin();
526         string::size_type longest_length = (*longest).length();
527
528         vector<string>::iterator i = longest;
529         ++i;
530
531         while (i != strings.end()) {
532
533                 string::size_type len = (*i).length();
534
535                 if (len > longest_length) {
536                         longest = i;
537                         longest_length = len;
538                 }
539
540                 ++i;
541         }
542
543         return *longest;
544 }
545
546 bool
547 ARDOUR_UI_UTILS::key_is_legal_for_numeric_entry (guint keyval)
548 {
549         /* we assume that this does not change over the life of the process
550          */
551
552         static int comma_decimal = -1;
553
554         switch (keyval) {
555         case GDK_period:
556         case GDK_comma:
557                 if (comma_decimal < 0) {
558                         std::lconv* lc = std::localeconv();
559                         if (strchr (lc->decimal_point, ',') != 0) {
560                                 comma_decimal = 1;
561                         } else {
562                                 comma_decimal = 0;
563                         }
564                 }
565                 break;
566         default:
567                 break;
568         }
569
570         switch (keyval) {
571         case GDK_decimalpoint:
572         case GDK_KP_Separator:
573                 return true;
574
575         case GDK_period:
576                 if (comma_decimal) {
577                         return false;
578                 } else {
579                         return true;
580                 }
581                 break;
582         case GDK_comma:
583                 if (comma_decimal) {
584                         return true;
585                 } else {
586                         return false;
587                 }
588                 break;
589         case GDK_minus:
590         case GDK_plus:
591         case GDK_0:
592         case GDK_1:
593         case GDK_2:
594         case GDK_3:
595         case GDK_4:
596         case GDK_5:
597         case GDK_6:
598         case GDK_7:
599         case GDK_8:
600         case GDK_9:
601         case GDK_KP_Add:
602         case GDK_KP_Subtract:
603         case GDK_KP_Decimal:
604         case GDK_KP_0:
605         case GDK_KP_1:
606         case GDK_KP_2:
607         case GDK_KP_3:
608         case GDK_KP_4:
609         case GDK_KP_5:
610         case GDK_KP_6:
611         case GDK_KP_7:
612         case GDK_KP_8:
613         case GDK_KP_9:
614         case GDK_Return:
615         case GDK_BackSpace:
616         case GDK_Delete:
617         case GDK_KP_Enter:
618         case GDK_Home:
619         case GDK_End:
620         case GDK_Left:
621         case GDK_Right:
622                 return true;
623
624         default:
625                 break;
626         }
627
628         return false;
629 }
630
631 void
632 ARDOUR_UI_UTILS::resize_window_to_proportion_of_monitor (Gtk::Window* window, int max_width, int max_height)
633 {
634         Glib::RefPtr<Gdk::Screen> screen = window->get_screen ();
635         Gdk::Rectangle monitor_rect;
636         screen->get_monitor_geometry (0, monitor_rect);
637
638         int const w = std::min (int (monitor_rect.get_width() * 0.8), max_width);
639         int const h = std::min (int (monitor_rect.get_height() * 0.8), max_height);
640
641         window->resize (w, h);
642 }
643
644
645 /** Replace _ with __ in a string; for use with menu item text to make underscores displayed correctly */
646 string
647 ARDOUR_UI_UTILS::escape_underscores (string const & s)
648 {
649         string o;
650         string::size_type const N = s.length ();
651
652         for (string::size_type i = 0; i < N; ++i) {
653                 if (s[i] == '_') {
654                         o += "__";
655                 } else {
656                         o += s[i];
657                 }
658         }
659
660         return o;
661 }
662
663 /** Replace < and > with &lt; and &gt; respectively to make < > display correctly in markup strings */
664 string
665 ARDOUR_UI_UTILS::escape_angled_brackets (string const & s)
666 {
667         string o = s;
668         boost::replace_all (o, "<", "&lt;");
669         boost::replace_all (o, ">", "&gt;");
670         return o;
671 }
672
673 Gdk::Color
674 ARDOUR_UI_UTILS::unique_random_color (list<Gdk::Color>& used_colors)
675 {
676         Gdk::Color newcolor;
677
678         while (1) {
679
680                 double h, s, v;
681
682                 h = fmod (random(), 360.0);
683                 s = (random() % 65535) / 65535.0;
684                 v = (random() % 65535) / 65535.0;
685
686                 s = min (0.5, s); /* not too saturated */
687                 v = max (0.9, v);  /* not too bright */
688                 newcolor.set_hsv (h, s, v);
689
690                 if (used_colors.size() == 0) {
691                         used_colors.push_back (newcolor);
692                         return newcolor;
693                 }
694
695                 for (list<Gdk::Color>::iterator i = used_colors.begin(); i != used_colors.end(); ++i) {
696                   Gdk::Color c = *i;
697                         float rdelta, bdelta, gdelta;
698
699                         rdelta = newcolor.get_red() - c.get_red();
700                         bdelta = newcolor.get_blue() - c.get_blue();
701                         gdelta = newcolor.get_green() - c.get_green();
702
703                         if (sqrt (rdelta*rdelta + bdelta*bdelta + gdelta*gdelta) > 25.0) {
704                                 /* different enough */
705                                 used_colors.push_back (newcolor);
706                                 return newcolor;
707                         }
708                 }
709
710                 /* XXX need throttle here to make sure we don't spin for ever */
711         }
712 }
713
714 string
715 ARDOUR_UI_UTILS::rate_as_string (float r)
716 {
717         char buf[32];
718         if (fmod (r, 1000.0f)) {
719                 snprintf (buf, sizeof (buf), "%.1f kHz", r/1000.0);
720         } else {
721                 snprintf (buf, sizeof (buf), "%.0f kHz", r/1000.0);
722         }
723         return buf;
724 }
725
726 bool
727 ARDOUR_UI_UTILS::windows_overlap (Gtk::Window *a, Gtk::Window *b)
728 {
729
730         if (!a || !b) {
731                 return false;
732         }
733         if (a->get_screen() == b->get_screen()) {
734                 gint ex, ey, ew, eh;
735                 gint mx, my, mw, mh;
736
737                 a->get_position (ex, ey);
738                 a->get_size (ew, eh);
739                 b->get_position (mx, my);
740                 b->get_size (mw, mh);
741
742                 GdkRectangle e;
743                 GdkRectangle m;
744                 GdkRectangle r;
745
746                 e.x = ex;
747                 e.y = ey;
748                 e.width = ew;
749                 e.height = eh;
750
751                 m.x = mx;
752                 m.y = my;
753                 m.width = mw;
754                 m.height = mh;
755
756                 if (gdk_rectangle_intersect (&e, &m, &r)) {
757                         return true;
758                 }
759         }
760         return false;
761 }
762
763 bool
764 ARDOUR_UI_UTILS::overwrite_file_dialog (Gtk::Window& parent, string title, string text)
765 {
766         ArdourDialog dialog (parent, title, true);
767         Label label (text);
768
769         dialog.get_vbox()->pack_start (label, true, true);
770         dialog.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
771         dialog.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
772         dialog.show_all ();
773
774         switch (dialog.run()) {
775         case RESPONSE_ACCEPT:
776                 return true;
777         case RESPONSE_CANCEL:
778         default:
779                 return false;
780         }
781 }