merge fix
[ardour.git] / libs / gtkmm2ext / gtk_ui.cc
1 /*
2     Copyright (C) 1999-2005 Paul Barton-Davis
3
4     This program is free software; you can 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     $Id$
19 */
20
21 #include <cmath>
22 #include <fcntl.h>
23 #include <signal.h>
24 #include <unistd.h>
25 #include <cerrno>
26 #include <climits>
27 #include <cctype>
28
29 #include <gtkmm.h>
30
31 #include "pbd/error.h"
32 #include "pbd/touchable.h"
33 #include "pbd/failed_constructor.h"
34 #include "pbd/pthread_utils.h"
35 #include "pbd/replace_all.h"
36
37 #include "gtkmm2ext/application.h"
38 #include "gtkmm2ext/gtk_ui.h"
39 #include "gtkmm2ext/textviewer.h"
40 #include "gtkmm2ext/popup.h"
41 #include "gtkmm2ext/utils.h"
42 #include "gtkmm2ext/window_title.h"
43 #include "gtkmm2ext/actions.h"
44 #include "gtkmm2ext/activatable.h"
45 #include "gtkmm2ext/actions.h"
46 #include "gtkmm2ext/gui_thread.h"
47
48 #include "i18n.h"
49
50 using namespace Gtkmm2ext;
51 using namespace Gtk;
52 using namespace Glib;
53 using namespace PBD;
54 using std::map;
55
56 UI       *UI::theGtkUI = 0;
57
58 BaseUI::RequestType Gtkmm2ext::NullMessage = BaseUI::new_request_type();
59 BaseUI::RequestType Gtkmm2ext::ErrorMessage = BaseUI::new_request_type();
60 BaseUI::RequestType Gtkmm2ext::TouchDisplay = BaseUI::new_request_type();
61 BaseUI::RequestType Gtkmm2ext::StateChange = BaseUI::new_request_type();
62 BaseUI::RequestType Gtkmm2ext::SetTip = BaseUI::new_request_type();
63 BaseUI::RequestType Gtkmm2ext::AddIdle = BaseUI::new_request_type();
64 BaseUI::RequestType Gtkmm2ext::AddTimeout = BaseUI::new_request_type();
65
66 #include "pbd/abstract_ui.cc"  /* instantiate the template */
67
68 template class AbstractUI<Gtkmm2ext::UIRequest>;
69
70 UI::UI (string namestr, int *argc, char ***argv)
71         : AbstractUI<UIRequest> (namestr)
72         , _receiver (*this)
73         , errors (0)
74           
75 {
76         theMain = new Main (argc, argv);
77
78         pthread_set_name ("gui");
79         
80         _active = false;
81
82         if (!theGtkUI) {
83                 theGtkUI = this;
84         } else {
85                 fatal << "duplicate UI requested" << endmsg;
86                 abort(); /* NOTREACHED */
87         }
88
89         /* the GUI event loop runs in the main thread of the app,
90            which is assumed to have called this.
91         */
92
93         run_loop_thread = Threads::Thread::self();
94         
95         /* store "this" as the UI-for-thread of this thread, same argument
96            as for previous line.
97         */
98
99         set_event_loop_for_thread (this);
100
101         /* attach our request source to the default main context */
102
103         attach_request_source ();
104
105         errors = new TextViewer (800,600);
106         errors->text().set_editable (false);
107         errors->text().set_name ("ErrorText");
108         errors->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("<Actions>/Editor/toggle-log-window")));
109
110         Glib::set_application_name(namestr);
111
112         WindowTitle title(Glib::get_application_name());
113         title += _("Log");
114         errors->set_title (title.get_string());
115
116         errors->dismiss_button().set_name ("ErrorLogCloseButton");
117         errors->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), (Window *) errors));
118         errors->set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY);
119
120         //load_rcfile (rcfile);
121
122         /* instantiate the Application singleton */
123
124         Application::instance();
125 }
126
127 UI::~UI ()
128 {
129         _receiver.hangup ();
130         delete (errors);
131 }
132
133 bool
134 UI::caller_is_ui_thread ()
135 {
136         return Threads::Thread::self() == run_loop_thread;
137 }
138
139 int
140 UI::load_rcfile (string path, bool themechange)
141 {
142         /* Yes, pointers to Glib::RefPtr.  If these are not kept around,
143          * a segfault somewhere deep in the wonderfully robust glib will result.
144          * This does not occur if wiget.get_style is used instead of rc.get_style below,
145          * except that doesn't actually work... 
146          */
147         
148         static Glib::RefPtr<Style>* fatal_style   = 0;
149         static Glib::RefPtr<Style>* error_style   = 0;
150         static Glib::RefPtr<Style>* warning_style = 0;
151         static Glib::RefPtr<Style>* info_style    = 0;
152
153         if (path.length() == 0) {
154                 return -1;
155         }
156
157         if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
158                 error << "UI: couldn't find rc file \""
159                       << path
160                       << '"'
161                       << endmsg;
162                 return -1;
163         }
164
165         RC rc (path.c_str());
166         //this is buggy in gtkmm for some reason, so use C
167         //RC::reset_styles (Gtk::Settings::get_default());
168         gtk_rc_reset_styles (gtk_settings_get_default());
169
170         theme_changed.emit();
171
172         if (themechange) {
173                 return 0; //Don't continue on every time there is a theme change
174         }
175
176         /* have to pack widgets into a toplevel window so that styles will stick */
177
178         Window temp_window (WINDOW_TOPLEVEL);
179         temp_window.ensure_style ();
180
181         HBox box;
182         Label fatal_widget;
183         Label error_widget;
184         Label warning_widget;
185         Label info_widget;
186         RefPtr<Gtk::Style> style;
187         RefPtr<TextBuffer> buffer (errors->text().get_buffer());
188
189         box.pack_start (fatal_widget);
190         box.pack_start (error_widget);
191         box.pack_start (warning_widget);
192         box.pack_start (info_widget);
193
194         error_ptag = buffer->create_tag();
195         error_mtag = buffer->create_tag();
196         fatal_ptag = buffer->create_tag();
197         fatal_mtag = buffer->create_tag();
198         warning_ptag = buffer->create_tag();
199         warning_mtag = buffer->create_tag();
200         info_ptag = buffer->create_tag();
201         info_mtag = buffer->create_tag();
202
203         fatal_widget.set_name ("FatalMessage");
204         delete fatal_style;
205
206         /* This next line and the similar ones below are sketchily
207          * guessed to fix #2885.  I think maybe that problems occur
208          * because with gtk_rc_get_style (to quote its docs) "no
209          * refcount is added to the returned style".  So I've switched
210          * this to use Glib::wrap with take_copy == true, which requires
211          * all the nasty casts and calls to plain-old-C GTK.
212          *
213          * At worst I think this causes a memory leak; at least it appears
214          * to fix the bug.
215          *
216          * I could be wrong about any or all of the above.
217          */
218         fatal_style = new Glib::RefPtr<Style> (Glib::wrap (gtk_rc_get_style (reinterpret_cast<GtkWidget*> (fatal_widget.gobj())), true));
219
220         fatal_ptag->property_font_desc().set_value((*fatal_style)->get_font());
221         fatal_ptag->property_foreground_gdk().set_value((*fatal_style)->get_fg(STATE_ACTIVE));
222         fatal_ptag->property_background_gdk().set_value((*fatal_style)->get_bg(STATE_ACTIVE));
223         fatal_mtag->property_font_desc().set_value((*fatal_style)->get_font());
224         fatal_mtag->property_foreground_gdk().set_value((*fatal_style)->get_fg(STATE_NORMAL));
225         fatal_mtag->property_background_gdk().set_value((*fatal_style)->get_bg(STATE_NORMAL));
226
227         error_widget.set_name ("ErrorMessage");
228         delete error_style;
229         error_style = new Glib::RefPtr<Style> (Glib::wrap (gtk_rc_get_style (reinterpret_cast<GtkWidget*> (error_widget.gobj())), true));
230
231         error_ptag->property_font_desc().set_value((*error_style)->get_font());
232         error_ptag->property_foreground_gdk().set_value((*error_style)->get_fg(STATE_ACTIVE));
233         error_ptag->property_background_gdk().set_value((*error_style)->get_bg(STATE_ACTIVE));
234         error_mtag->property_font_desc().set_value((*error_style)->get_font());
235         error_mtag->property_foreground_gdk().set_value((*error_style)->get_fg(STATE_NORMAL));
236         error_mtag->property_background_gdk().set_value((*error_style)->get_bg(STATE_NORMAL));
237
238         warning_widget.set_name ("WarningMessage");
239         delete warning_style;
240         warning_style = new Glib::RefPtr<Style> (Glib::wrap (gtk_rc_get_style (reinterpret_cast<GtkWidget*> (warning_widget.gobj())), true));
241
242         warning_ptag->property_font_desc().set_value((*warning_style)->get_font());
243         warning_ptag->property_foreground_gdk().set_value((*warning_style)->get_fg(STATE_ACTIVE));
244         warning_ptag->property_background_gdk().set_value((*warning_style)->get_bg(STATE_ACTIVE));
245         warning_mtag->property_font_desc().set_value((*warning_style)->get_font());
246         warning_mtag->property_foreground_gdk().set_value((*warning_style)->get_fg(STATE_NORMAL));
247         warning_mtag->property_background_gdk().set_value((*warning_style)->get_bg(STATE_NORMAL));
248
249         info_widget.set_name ("InfoMessage");
250         delete info_style;
251         info_style = new Glib::RefPtr<Style> (Glib::wrap (gtk_rc_get_style (reinterpret_cast<GtkWidget*> (info_widget.gobj())), true));
252
253         info_ptag->property_font_desc().set_value((*info_style)->get_font());
254         info_ptag->property_foreground_gdk().set_value((*info_style)->get_fg(STATE_ACTIVE));
255         info_ptag->property_background_gdk().set_value((*info_style)->get_bg(STATE_ACTIVE));
256         info_mtag->property_font_desc().set_value((*info_style)->get_font());
257         info_mtag->property_foreground_gdk().set_value((*info_style)->get_fg(STATE_NORMAL));
258         info_mtag->property_background_gdk().set_value((*info_style)->get_bg(STATE_NORMAL));
259
260         return 0;
261 }
262
263 void
264 UI::run (Receiver &old_receiver)
265 {
266         _receiver.listen_to (error);
267         _receiver.listen_to (info);
268         _receiver.listen_to (warning);
269         _receiver.listen_to (fatal);
270
271         /* stop the old receiver (text/console) once we hit the first idle */
272
273         Glib::signal_idle().connect (bind_return (mem_fun (old_receiver, &Receiver::hangup), false));
274
275         if (starting ()) {
276                 return;
277         }
278
279         _active = true;
280         theMain->run ();
281         _active = false;
282
283         return;
284 }
285
286 bool
287 UI::running ()
288 {
289         return _active;
290 }
291
292 void
293 UI::quit ()
294 {
295         UIRequest *req = get_request (Quit);
296
297         if (req == 0) {
298                 return;
299         }
300
301         send_request (req);
302 }
303
304 static bool idle_quit ()
305 {
306         Main::quit ();
307         return true;
308 }
309
310 void
311 UI::do_quit ()
312 {
313         if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
314                 Main::quit ();
315         } else {
316                 Glib::signal_idle().connect (sigc::ptr_fun (idle_quit));
317         }
318 }
319
320 void
321 UI::touch_display (Touchable *display)
322 {
323         UIRequest *req = get_request (TouchDisplay);
324
325         if (req == 0) {
326                 return;
327         }
328
329         req->display = display;
330
331         send_request (req);
332 }
333
334 void
335 UI::set_tip (Widget &w, const gchar *tip)
336 {
337         set_tip(&w, tip, "");
338 }
339
340 void
341 UI::set_tip (Widget &w, const std::string& tip)
342 {
343         set_tip(&w, tip.c_str(), "");
344 }
345
346 void
347 UI::set_tip (Widget *w, const gchar *tip, const gchar *hlp)
348 {
349         UIRequest *req = get_request (SetTip);
350
351         std::string msg(tip);
352
353         Glib::RefPtr<Gtk::Action> action = w->get_action();
354
355         if (!action) {
356                 Gtkmm2ext::Activatable* activatable;
357                 if ((activatable = dynamic_cast<Gtkmm2ext::Activatable*>(w))) {
358                         action = activatable->get_related_action();
359                 }
360         }
361
362         if (action) {
363                 Gtk::AccelKey key;
364                 ustring ap = action->get_accel_path();
365                 if (!ap.empty()) {
366                         string shortcut = ActionManager::get_key_representation (ap, key);
367                         if (!shortcut.empty()) {
368                                 replace_all (shortcut, "<", "");
369                                 replace_all (shortcut, ">", "-");
370                                 msg.append(_("\n\nShortcut: ")).append (shortcut);
371                         }
372                 }
373         }
374
375         if (req == 0) {
376                 return;
377         }
378
379
380         req->widget = w;
381         req->msg = msg.c_str();
382         req->msg2 = hlp;
383
384         send_request (req);
385 }
386
387 void
388 UI::set_state (Widget *w, StateType state)
389 {
390         UIRequest *req = get_request (StateChange);
391
392         if (req == 0) {
393                 return;
394         }
395
396         req->new_state = state;
397         req->widget = w;
398
399         send_request (req);
400 }
401
402 void
403 UI::idle_add (int (*func)(void *), void *arg)
404 {
405         UIRequest *req = get_request (AddIdle);
406
407         if (req == 0) {
408                 return;
409         }
410
411         req->function = func;
412         req->arg = arg;
413
414         send_request (req);
415 }
416
417 /* END abstract_ui interfaces */
418
419 /** Create a PBD::EventLoop::InvalidationRecord and attach a callback
420  *  to a given sigc::trackable so that PBD::EventLoop::invalidate_request
421  *  is called when that trackable is destroyed.
422  */
423 PBD::EventLoop::InvalidationRecord*
424 __invalidator (sigc::trackable& trackable, const char* file, int line)
425 {
426         PBD::EventLoop::InvalidationRecord* ir = new PBD::EventLoop::InvalidationRecord;
427
428         ir->file = file;
429         ir->line = line;
430
431         trackable.add_destroy_notify_callback (ir, PBD::EventLoop::invalidate_request);
432
433         return ir;
434 }
435
436 void
437 UI::do_request (UIRequest* req)
438 {
439         if (req->type == ErrorMessage) {
440
441                 process_error_message (req->chn, req->msg);
442                 free (const_cast<char*>(req->msg)); /* it was strdup'ed */
443                 req->msg = 0; /* don't free it again in the destructor */
444
445         } else if (req->type == Quit) {
446
447                 do_quit ();
448
449         } else if (req->type == CallSlot) {
450 #ifndef NDEBUG
451                 if (getenv ("DEBUG_THREADED_SIGNALS")) {
452                         cerr << "call slot for " << name() << endl;
453                 }
454 #endif
455                 req->the_slot ();
456
457         } else if (req->type == TouchDisplay) {
458
459                 req->display->touch ();
460                 if (req->display->delete_after_touch()) {
461                         delete req->display;
462                 }
463
464         } else if (req->type == StateChange) {
465
466                 req->widget->set_state (req->new_state);
467
468         } else if (req->type == SetTip) {
469
470                 gtk_widget_set_tooltip_markup (req->widget->gobj(), req->msg);
471
472         } else {
473
474                 error << "GtkUI: unknown request type "
475                       << (int) req->type
476                       << endmsg;
477         }
478 }
479
480 /*======================================================================
481   Error Display
482   ======================================================================*/
483
484 void
485 UI::dump_errors (std::ostream& ostr)
486 {
487         Glib::Threads::Mutex::Lock lm (error_lock);
488         ostr << endl << X_("Errors/Messages:") << endl;
489         for (list<string>::const_iterator i = error_stack.begin(); i != error_stack.end(); ++i) {
490                 ostr << *i << endl;
491         }
492         ostr << endl;
493 }
494
495 void
496 UI::receive (Transmitter::Channel chn, const char *str)
497 {
498         {
499                 Glib::Threads::Mutex::Lock lm (error_lock);
500                 switch (chn) {
501                 case Transmitter::Fatal:
502                         error_stack.push_back (string (X_("FATAL: ")) + str);
503                         break;
504                 case Transmitter::Error:
505                         error_stack.push_back (string (X_("ERROR: ")) + str);
506                         break;
507                 case Transmitter::Warning:
508                         error_stack.push_back (string (X_("WARNING: ")) + str);
509                         break;
510                 case Transmitter::Info:
511                         error_stack.push_back (string (X_("INFO: ")) + str);
512                         break;
513                 case Transmitter::Throw:
514                         error_stack.push_back (string (X_("THROW: ")) + str);
515                         break;
516                 }
517         }
518
519         if (caller_is_ui_thread()) {
520                 process_error_message (chn, str);
521         } else {
522                 UIRequest* req = get_request (ErrorMessage);
523
524                 if (req == 0) {
525                         return;
526                 }
527
528                 req->chn = chn;
529                 req->msg = strdup (str);
530
531                 send_request (req);
532         }
533 }
534
535 #define OLD_STYLE_ERRORS 1
536
537 void
538 UI::process_error_message (Transmitter::Channel chn, const char *str)
539 {
540         RefPtr<Style> style;
541         RefPtr<TextBuffer::Tag> ptag;
542         RefPtr<TextBuffer::Tag> mtag;
543         const char *prefix;
544         size_t prefix_len;
545         bool fatal_received = false;
546 #ifndef OLD_STYLE_ERRORS
547         PopUp* popup = new PopUp (WIN_POS_CENTER, 0, true);
548 #endif
549
550         switch (chn) {
551         case Transmitter::Fatal:
552                 prefix = "[FATAL]: ";
553                 ptag = fatal_ptag;
554                 mtag = fatal_mtag;
555                 prefix_len = 9;
556                 fatal_received = true;
557                 break;
558         case Transmitter::Error:
559 #if OLD_STYLE_ERRORS
560                 prefix = "[ERROR]: ";
561                 ptag = error_ptag;
562                 mtag = error_mtag;
563                 prefix_len = 9;
564 #else
565                 popup->set_name ("ErrorMessage");
566                 popup->set_text (str);
567                 popup->touch ();
568                 return;
569 #endif
570                 break;
571         case Transmitter::Info:
572 #if OLD_STYLE_ERRORS
573                 prefix = "[INFO]: ";
574                 ptag = info_ptag;
575                 mtag = info_mtag;
576                 prefix_len = 8;
577 #else
578                 popup->set_name ("InfoMessage");
579                 popup->set_text (str);
580                 popup->touch ();
581                 return;
582 #endif
583
584                 break;
585         case Transmitter::Warning:
586 #if OLD_STYLE_ERRORS
587                 prefix = "[WARNING]: ";
588                 ptag = warning_ptag;
589                 mtag = warning_mtag;
590                 prefix_len = 11;
591 #else
592                 popup->set_name ("WarningMessage");
593                 popup->set_text (str);
594                 popup->touch ();
595                 return;
596 #endif
597                 break;
598         default:
599                 /* no choice but to use text/console output here */
600                 cerr << "programmer error in UI::check_error_messages (channel = " << chn << ")\n";
601                 ::exit (1);
602         }
603
604         errors->text().get_buffer()->begin_user_action();
605
606         if (fatal_received) {
607                 handle_fatal (str);
608         } else {
609
610                 if (!ptag || !mtag) {
611                         /* oops, message sent before we set up tags - don't crash */
612                         cerr << prefix << str << endl;
613                 } else {
614                         display_message (prefix, prefix_len, ptag, mtag, str);
615                 }
616         }
617
618         errors->text().get_buffer()->end_user_action();
619 }
620
621 void
622 UI::show_errors ()
623 {
624         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-log-window"));
625         if (!act) {
626                 return;
627         }
628
629         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
630         if (tact) {
631                 tact->set_active ();
632         }
633 }
634
635 void
636 UI::toggle_errors ()
637 {
638         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-log-window"));
639         if (!act) {
640                 return;
641         }
642
643         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
644         
645         if (tact->get_active()) {
646                 errors->set_position (WIN_POS_MOUSE);
647                 errors->show ();
648         } else {
649                 errors->hide ();
650         }
651 }
652
653 void
654 UI::display_message (const char *prefix, gint /*prefix_len*/, RefPtr<TextBuffer::Tag> ptag, RefPtr<TextBuffer::Tag> mtag, const char *msg)
655 {
656         RefPtr<TextBuffer> buffer (errors->text().get_buffer());
657
658         buffer->insert_with_tag(buffer->end(), prefix, ptag);
659         buffer->insert_with_tag(buffer->end(), msg, mtag);
660         buffer->insert_with_tag(buffer->end(), "\n", mtag);
661
662         errors->scroll_to_bottom ();
663 }
664
665 void
666 UI::handle_fatal (const char *message)
667 {
668         Dialog win;
669         Label label (message);
670         Button quit (_("Press To Exit"));
671         HBox hpacker;
672
673         win.set_default_size (400, 100);
674
675         WindowTitle title(Glib::get_application_name());
676         title += ": Fatal Error";
677         win.set_title (title.get_string());
678
679         win.set_position (WIN_POS_MOUSE);
680         win.set_border_width (12);
681
682         win.get_vbox()->pack_start (label, true, true);
683         hpacker.pack_start (quit, true, false);
684         win.get_vbox()->pack_start (hpacker, false, false);
685
686         quit.signal_clicked().connect(mem_fun(*this,&UI::quit));
687
688         win.show_all ();
689         win.set_modal (true);
690
691         theMain->run ();
692
693         _exit (1);
694 }
695
696 void
697 UI::popup_error (const string& text)
698 {
699         if (!caller_is_ui_thread()) {
700                 error << "non-UI threads can't use UI::popup_error"
701                       << endmsg;
702                 return;
703         }
704
705         MessageDialog msg (text);
706         msg.set_title (string_compose (_("I'm sorry %1, I can't do that"), g_get_user_name()));
707         msg.set_wmclass (X_("error"), name());
708         msg.set_position (WIN_POS_MOUSE);
709         msg.run ();
710 }
711
712 void
713 UI::flush_pending ()
714 {
715         if (!caller_is_ui_thread()) {
716                 error << "non-UI threads cannot call UI::flush_pending()"
717                       << endmsg;
718                 return;
719         }
720
721         gtk_main_iteration();
722
723         while (gtk_events_pending()) {
724                 gtk_main_iteration();
725         }
726 }
727
728 bool
729 UI::just_hide_it (GdkEventAny* /*ev*/, Window *win)
730 {
731         win->hide ();
732         return true;
733 }
734
735 Gdk::Color
736 UI::get_color (const string& prompt, bool& picked, const Gdk::Color* initial)
737 {
738         Gdk::Color color;
739
740         ColorSelectionDialog color_dialog (prompt);
741
742         color_dialog.set_modal (true);
743         color_dialog.get_cancel_button()->signal_clicked().connect (bind (mem_fun (*this, &UI::color_selection_done), false));
744         color_dialog.get_ok_button()->signal_clicked().connect (bind (mem_fun (*this, &UI::color_selection_done), true));
745         color_dialog.signal_delete_event().connect (mem_fun (*this, &UI::color_selection_deleted));
746
747         if (initial) {
748                 color_dialog.get_colorsel()->set_current_color (*initial);
749         }
750
751         color_dialog.show_all ();
752         color_picked = false;
753         picked = false;
754
755         Main::run();
756
757         color_dialog.hide_all ();
758
759         if (color_picked) {
760                 Gdk::Color f_rgba = color_dialog.get_colorsel()->get_current_color ();
761                 color.set_red(f_rgba.get_red());
762                 color.set_green(f_rgba.get_green());
763                 color.set_blue(f_rgba.get_blue());
764
765                 picked = true;
766         }
767
768         return color;
769 }
770
771 void
772 UI::color_selection_done (bool status)
773 {
774         color_picked = status;
775         Main::quit ();
776 }
777
778 bool
779 UI::color_selection_deleted (GdkEventAny* /*ev*/)
780 {
781         Main::quit ();
782         return true;
783 }