2 Copyright (C) 1999 Paul Barton-Davis
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.
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.
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.
24 #include <gtk/gtkpaned.h>
27 #include <gtkmm/widget.h>
28 #include <gtkmm/button.h>
29 #include <gtkmm/window.h>
30 #include <gtkmm/paned.h>
31 #include <gtkmm/label.h>
32 #include <gtkmm/comboboxtext.h>
33 #include <gtkmm/tooltip.h>
35 #include "gtkmm2ext/utils.h"
42 Gtkmm2ext::init (const char* localedir)
45 (void) bindtextdomain(PACKAGE, localedir);
46 (void) bind_textdomain_codeset (PACKAGE, "UTF-8");
51 Gtkmm2ext::get_ink_pixel_size (Glib::RefPtr<Pango::Layout> layout,
55 Pango::Rectangle ink_rect = layout->get_ink_extents ();
57 width = PANGO_PIXELS(ink_rect.get_width());
58 height = PANGO_PIXELS(ink_rect.get_height());
62 Gtkmm2ext::get_pixel_size (Glib::RefPtr<Pango::Layout> layout,
66 layout->get_pixel_size (width, height);
70 Gtkmm2ext::set_size_request_to_display_given_text (Gtk::Widget &w, const gchar *text,
71 gint hpadding, gint vpadding)
76 get_pixel_size (w.create_pango_layout (text), width, height);
77 w.set_size_request(width + hpadding, height + vpadding);
80 /** Set width request to display given text, and height to display anything.
81 This is useful for setting many widgets to the same height for consistency. */
83 Gtkmm2ext::set_size_request_to_display_given_text_width (Gtk::Widget& w,
88 static const gchar* vtext = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
93 get_pixel_size (w.create_pango_layout (htext), hwidth, hheight);
96 get_pixel_size (w.create_pango_layout (vtext), vwidth, vheight);
98 w.set_size_request(hwidth + hpadding, vheight + vpadding);
102 Gtkmm2ext::set_height_request_to_display_any_text (Gtk::Widget& w, gint vpadding)
104 static const gchar* vtext = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
109 get_pixel_size (w.create_pango_layout (vtext), width, height);
111 w.set_size_request(-1, height + vpadding);
115 Gtkmm2ext::set_size_request_to_display_given_text (Gtk::Widget &w, std::string const & text,
116 gint hpadding, gint vpadding)
121 get_pixel_size (w.create_pango_layout (text), width, height);
122 w.set_size_request(width + hpadding, height + vpadding);
126 Gtkmm2ext::set_size_request_to_display_given_text (Gtk::Widget &w,
127 const std::vector<std::string>& strings,
128 gint hpadding, gint vpadding)
135 const vector<string>* to_use;
136 vector<string>::const_iterator i;
138 for (i = strings.begin(); i != strings.end(); ++i) {
139 if ((*i).find_first_of ("gy") != string::npos) {
140 /* contains a descender */
145 if (i == strings.end()) {
146 /* make a copy of the strings then add one that has a descender */
148 copy.push_back ("g");
154 for (vector<string>::const_iterator i = to_use->begin(); i != to_use->end(); ++i) {
155 get_pixel_size (w.create_pango_layout (*i), width, height);
156 width_max = max(width_max,width);
157 height_max = max(height_max, height);
160 w.set_size_request(width_max + hpadding, height_max + vpadding);
163 /** This version specifies horizontal padding in text to avoid assumptions
164 about font size. Should be used anywhere padding is used to avoid text,
167 Gtkmm2ext::set_size_request_to_display_given_text (Gtk::Widget& w,
168 const std::vector<std::string>& strings,
169 const std::string& hpadding,
176 for (vector<string>::const_iterator i = strings.begin(); i != strings.end(); ++i) {
178 get_pixel_size (w.create_pango_layout (*i), width, height);
179 width_max = max(width_max,width);
180 height_max = max(height_max, height);
185 get_pixel_size (w.create_pango_layout (hpadding), pad_width, pad_height);
187 w.set_size_request(width_max + pad_width, height_max + vpadding);
191 demultiply_alpha (guint8 src,
194 /* cairo pixel buffer data contains RGB values with the alpha
195 values premultiplied.
197 GdkPixbuf pixel buffer data contains RGB values without the
200 this removes the alpha component from the cairo version and
201 returns the GdkPixbuf version.
203 return alpha ? ((guint (src) << 8) - src) / alpha : 0;
207 Gtkmm2ext::convert_bgra_to_rgba (guint8 const* src,
212 guint8 const* src_pixel = src;
213 guint8* dst_pixel = dst;
215 /* cairo pixel data is endian-dependent ARGB with A in the most significant 8 bits,
216 with premultipled alpha values (see preceding function)
218 GdkPixbuf pixel data is non-endian-dependent RGBA with R in the lowest addressable
219 8 bits, and non-premultiplied alpha values.
221 convert from the cairo values to the GdkPixbuf ones.
224 for (int y = 0; y < height; y++) {
225 for (int x = 0; x < width; x++) {
226 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
227 /* Cairo [ B G R A ] is actually [ B G R A ] in memory SOURCE
229 Pixbuf [ R G B A ] is actually [ R G B A ] in memory DEST
231 dst_pixel[0] = demultiply_alpha (src_pixel[2],
232 src_pixel[3]); // R [0] <= [ 2 ]
233 dst_pixel[1] = demultiply_alpha (src_pixel[1],
234 src_pixel[3]); // G [1] <= [ 1 ]
235 dst_pixel[2] = demultiply_alpha (src_pixel[0],
236 src_pixel[3]); // B [2] <= [ 0 ]
237 dst_pixel[3] = src_pixel[3]; // alpha
239 #elif G_BYTE_ORDER == G_BIG_ENDIAN
240 /* Cairo [ B G R A ] is actually [ A R G B ] in memory SOURCE
242 Pixbuf [ R G B A ] is actually [ R G B A ] in memory DEST
244 dst_pixel[0] = demultiply_alpha (src_pixel[1],
245 src_pixel[0]); // R [0] <= [ 1 ]
246 dst_pixel[1] = demultiply_alpha (src_pixel[2],
247 src_pixel[0]); // G [1] <= [ 2 ]
248 dst_pixel[2] = demultiply_alpha (src_pixel[3],
249 src_pixel[0]); // B [2] <= [ 3 ]
250 dst_pixel[3] = src_pixel[0]; // alpha
253 #error ardour does not currently support PDP-endianess
262 Glib::RefPtr<Gdk::Pixbuf>
263 Gtkmm2ext::pixbuf_from_string(const string& name, const Pango::FontDescription& font, int clip_width, int clip_height, Gdk::Color fg)
265 static Glib::RefPtr<Gdk::Pixbuf>* empty_pixbuf = 0;
268 if (empty_pixbuf == 0) {
269 empty_pixbuf = new Glib::RefPtr<Gdk::Pixbuf>;
270 *empty_pixbuf = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, clip_width, clip_height);
272 return *empty_pixbuf;
275 if (clip_width <= 0 || clip_height <= 0) {
276 /* negative values mean padding around natural size */
278 pixel_size (name, font, width, height);
279 if (clip_width <= 0) {
280 clip_width = width - clip_width;
282 if (clip_height <= 0) {
283 clip_height = height - clip_height;
287 Glib::RefPtr<Gdk::Pixbuf> buf = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, clip_width, clip_height);
289 cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, clip_width, clip_height);
290 cairo_t* cr = cairo_create (surface);
291 cairo_text_extents_t te;
293 cairo_set_source_rgba (cr, fg.get_red_p(), fg.get_green_p(), fg.get_blue_p(), 1.0);
294 cairo_select_font_face (cr, font.get_family().c_str(),
295 CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
296 cairo_set_font_size (cr, font.get_size() / Pango::SCALE);
297 cairo_text_extents (cr, name.c_str(), &te);
299 cairo_move_to (cr, 0.5, int (0.5 - te.height / 2 - te.y_bearing + clip_height / 2));
300 cairo_show_text (cr, name.c_str());
302 convert_bgra_to_rgba(cairo_image_surface_get_data (surface), buf->get_pixels(), clip_width, clip_height);
305 cairo_surface_destroy(surface);
311 Gtkmm2ext::set_popdown_strings (Gtk::ComboBoxText& cr, const vector<string>& strings)
313 vector<string>::const_iterator i;
317 for (i = strings.begin(); i != strings.end(); ++i) {
323 Gtkmm2ext::get_popdown_strings (Gtk::ComboBoxText& cr, std::vector<std::string>& strings)
326 Glib::RefPtr<const Gtk::TreeModel> m = cr.get_model();
330 for(Gtk::TreeModel::iterator i = m->children().begin(); i != m->children().end(); ++i) {
332 (*i)->get_value(0, txt);
333 strings.push_back (txt);
338 Gtkmm2ext::get_popdown_string_count (Gtk::ComboBoxText& cr)
340 Glib::RefPtr<const Gtk::TreeModel> m = cr.get_model();
344 return m->children().size();
348 Gtkmm2ext::contains_value (Gtk::ComboBoxText& cr, const std::string text)
350 std::vector<std::string> s;
351 get_popdown_strings (cr, s);
352 return (std::find (s.begin(), s.end(), text) != s.end());
356 Gtkmm2ext::set_active_text_if_present (Gtk::ComboBoxText& cr, const std::string text)
358 if (contains_value(cr, text)) {
359 cr.set_active_text (text);
366 Gtkmm2ext::get_paned_handle (Gtk::Paned& paned)
368 return GTK_PANED(paned.gobj())->handle;
372 Gtkmm2ext::set_decoration (Gtk::Window* win, Gdk::WMDecoration decor)
374 win->get_window()->set_decorations (decor);
377 void Gtkmm2ext::set_treeview_header_as_default_label(Gtk::TreeViewColumn* c)
379 gtk_tree_view_column_set_widget( c->gobj(), GTK_WIDGET(0) );
383 Gtkmm2ext::detach_menu (Gtk::Menu& menu)
385 /* its possible for a Gtk::Menu to have no gobj() because it has
386 not yet been instantiated. Catch this and provide a safe
390 if (menu.get_attach_widget()) {
397 Gtkmm2ext::possibly_translate_keyval_to_make_legal_accelerator (uint32_t& keyval)
399 int fakekey = GDK_VoidSymbol;
403 case GDK_ISO_Left_Tab:
408 fakekey = GDK_uparrow;
412 fakekey = GDK_downarrow;
416 fakekey = GDK_rightarrow;
420 fakekey = GDK_leftarrow;
424 fakekey = GDK_3270_Enter;
435 if (fakekey != GDK_VoidSymbol) {
444 Gtkmm2ext::possibly_translate_legal_accelerator_to_real_key (uint32_t keyval)
479 Gtkmm2ext::physical_screen_height (Glib::RefPtr<Gdk::Window> win)
481 GdkScreen* scr = gdk_screen_get_default();
485 gint monitor = gdk_screen_get_monitor_at_window (scr, win->gobj());
486 gdk_screen_get_monitor_geometry (scr, monitor, &r);
489 return gdk_screen_get_height (scr);
494 Gtkmm2ext::physical_screen_width (Glib::RefPtr<Gdk::Window> win)
496 GdkScreen* scr = gdk_screen_get_default();
500 gint monitor = gdk_screen_get_monitor_at_window (scr, win->gobj());
501 gdk_screen_get_monitor_geometry (scr, monitor, &r);
504 return gdk_screen_get_width (scr);
509 Gtkmm2ext::container_clear (Gtk::Container& c)
511 list<Gtk::Widget*> children = c.get_children();
512 for (list<Gtk::Widget*>::iterator child = children.begin(); child != children.end(); ++child) {
518 Gtkmm2ext::rounded_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
520 rounded_rectangle (context->cobj(), x, y, w, h, r);
523 Gtkmm2ext::rounded_top_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
525 rounded_top_rectangle (context->cobj(), x, y, w, h, r);
528 Gtkmm2ext::rounded_top_left_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
530 rounded_top_left_rectangle (context->cobj(), x, y, w, h, r);
533 Gtkmm2ext::rounded_top_right_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
535 rounded_top_right_rectangle (context->cobj(), x, y, w, h, r);
538 Gtkmm2ext::rounded_top_half_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
540 rounded_top_half_rectangle (context->cobj(), x, y, w, h, r);
543 Gtkmm2ext::rounded_bottom_half_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
545 rounded_bottom_half_rectangle (context->cobj(), x, y, w, h, r);
549 Gtkmm2ext::rounded_left_half_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
551 rounded_left_half_rectangle (context->cobj(), x, y, w, h, r);
555 Gtkmm2ext::rounded_right_half_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
557 rounded_right_half_rectangle (context->cobj(), x, y, w, h, r);
561 Gtkmm2ext::rounded_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
563 double degrees = M_PI / 180.0;
565 cairo_new_sub_path (cr);
566 cairo_arc (cr, x + w - r, y + r, r, -90 * degrees, 0 * degrees); //tr
567 cairo_arc (cr, x + w - r, y + h - r, r, 0 * degrees, 90 * degrees); //br
568 cairo_arc (cr, x + r, y + h - r, r, 90 * degrees, 180 * degrees); //bl
569 cairo_arc (cr, x + r, y + r, r, 180 * degrees, 270 * degrees); //tl
570 cairo_close_path (cr);
574 Gtkmm2ext::rounded_left_half_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
576 double degrees = M_PI / 180.0;
578 cairo_new_sub_path (cr);
579 cairo_line_to (cr, x+w, y); // tr
580 cairo_line_to (cr, x+w, y + h); // br
581 cairo_arc (cr, x + r, y + h - r, r, 90 * degrees, 180 * degrees); //bl
582 cairo_arc (cr, x + r, y + r, r, 180 * degrees, 270 * degrees); //tl
583 cairo_close_path (cr);
587 Gtkmm2ext::rounded_right_half_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
589 double degrees = M_PI / 180.0;
591 cairo_new_sub_path (cr);
592 cairo_arc (cr, x + w - r, y + r, r, -90 * degrees, 0 * degrees); //tr
593 cairo_arc (cr, x + w - r, y + h - r, r, 0 * degrees, 90 * degrees); //br
594 cairo_line_to (cr, x, y + h); // bl
595 cairo_line_to (cr, x, y); // tl
596 cairo_close_path (cr);
600 Gtkmm2ext::rounded_top_half_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
602 double degrees = M_PI / 180.0;
604 cairo_new_sub_path (cr);
605 cairo_move_to (cr, x+w, y+h);
606 cairo_line_to (cr, x, y+h);
607 cairo_arc (cr, x + r, y + r, r, 180 * degrees, 270 * degrees); //tl
608 cairo_arc (cr, x + w - r, y + r, r, -90 * degrees, 0 * degrees); //tr
609 cairo_close_path (cr);
613 Gtkmm2ext::rounded_bottom_half_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
615 double degrees = M_PI / 180.0;
617 cairo_new_sub_path (cr);
618 cairo_move_to (cr, x, y);
619 cairo_line_to (cr, x+w, y);
620 cairo_arc (cr, x + w - r, y + h - r, r, 0 * degrees, 90 * degrees); //br
621 cairo_arc (cr, x + r, y + h - r, r, 90 * degrees, 180 * degrees); //bl
622 cairo_close_path (cr);
627 Gtkmm2ext::rounded_top_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
629 double degrees = M_PI / 180.0;
631 cairo_new_sub_path (cr);
632 cairo_move_to (cr, x+w, y+h);
633 cairo_line_to (cr, x, y+h);
634 cairo_arc (cr, x + r, y + r, r, 180 * degrees, 270 * degrees); //tl
635 cairo_arc (cr, x + w - r, y + r, r, -90 * degrees, 0 * degrees); //tr
636 cairo_close_path (cr);
640 Gtkmm2ext::rounded_top_left_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
648 cairo_move_to (cr, x+r,y); // Move to A
649 cairo_line_to (cr, x+w,y); // Straight line to B
650 cairo_line_to (cr, x+w,y+h); // Move to E
651 cairo_line_to (cr, x,y+h); // Line to F
652 cairo_line_to (cr, x,y+r); // Line to H
653 cairo_curve_to (cr, x,y,x,y,x+r,y); // Curve to A
657 Gtkmm2ext::rounded_top_right_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
665 cairo_move_to (cr, x,y); // Move to A
666 cairo_line_to (cr, x+w-r,y); // Straight line to B
667 cairo_curve_to (cr, x+w,y,x+w,y,x+w,y+r); // Curve to C, Control points are both at Q
668 cairo_line_to (cr, x+w,y+h); // Move to E
669 cairo_line_to (cr, x,y+h); // Line to F
670 cairo_line_to (cr, x,y); // Line to A
673 Glib::RefPtr<Gdk::Window>
674 Gtkmm2ext::window_to_draw_on (Gtk::Widget& w, Gtk::Widget** parent)
676 if (w.get_has_window()) {
677 return w.get_window();
680 (*parent) = w.get_parent();
683 if ((*parent)->get_has_window()) {
684 return (*parent)->get_window ();
686 (*parent) = (*parent)->get_parent ();
689 return Glib::RefPtr<Gdk::Window> ();
693 Gtkmm2ext::pixel_width (const string& str, const Pango::FontDescription& font)
695 Glib::RefPtr<Pango::Context> context = Glib::wrap (gdk_pango_context_get());
696 Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create (context);
698 layout->set_font_description (font);
699 layout->set_text (str);
702 Gtkmm2ext::get_ink_pixel_size (layout, width, height);
705 // Pango returns incorrect text width on some OS X
706 // So we have to make a correction
707 // To determine the correct indent take the largest symbol for which the width is correct
708 // and make the calculation
710 // see also libs/canvas/text.cc
712 layout->set_text ("H");
713 layout->get_pixel_size (cor_width, height);
714 width += cor_width * 1.5;
721 Gtkmm2ext::pixel_size (const string& str, const Pango::FontDescription& font, int& width, int& height)
724 Glib::RefPtr<Pango::Layout> layout = foo.create_pango_layout ("");
726 layout->set_font_description (font);
727 layout->set_text (str);
729 Gtkmm2ext::get_ink_pixel_size (layout, width, height);
734 Gtkmm2ext::fit_to_pixels (const string& str, int pixel_width, Pango::FontDescription& font, int& actual_width, bool with_ellipses)
736 /* DECEMBER 2011: THIS PROTOTYPE OF fit_to_pixels() IS NOT USED
737 ANYWHERE AND HAS NOT BEEN TESTED.
740 Glib::RefPtr<Pango::Layout> layout = foo.create_pango_layout (str);
741 Glib::RefPtr<const Pango::LayoutLine> line;
743 layout->set_font_description (font);
744 layout->set_width (pixel_width * PANGO_SCALE);
747 layout->set_ellipsize (Pango::ELLIPSIZE_END);
749 layout->set_wrap (Pango::WRAP_CHAR);
752 line = layout->get_line (0);
754 /* XXX: might need special care to get the ellipsis character, not sure
758 string s = string (layout->get_text ().substr(line->get_start_index(), line->get_length()));
760 cerr << "fit to pixels of " << str << " returns " << s << endl;
766 /** Try to fit a string into a given horizontal space by ellipsizing it.
767 * @param cr Cairo context in which the text will be plotted.
769 * @param avail Available horizontal space.
770 * @return (Text, possibly ellipsized) and (horizontal size of text)
773 std::pair<std::string, double>
774 Gtkmm2ext::fit_to_pixels (cairo_t* cr, std::string name, double avail)
776 /* XXX hopefully there exists a more efficient way of doing this */
778 bool abbreviated = false;
782 cairo_text_extents_t ext;
783 cairo_text_extents (cr, name.c_str(), &ext);
785 if (ext.width < avail || name.length() <= 4) {
791 name = name.substr (0, name.length() - 4) + "...";
793 name = name.substr (0, name.length() - 3) + "...";
798 return std::make_pair (name, width);
802 Gtkmm2ext::left_aligned_label (string const & t)
804 Gtk::Label* l = new Gtk::Label (t);
805 l->set_alignment (0, 0.5);
810 Gtkmm2ext::right_aligned_label (string const & t)
812 Gtk::Label* l = new Gtk::Label (t);
813 l->set_alignment (1, 0.5);
818 make_null_tooltip (int, int, bool, const Glib::RefPtr<Gtk::Tooltip>& t)
820 t->set_tip_area (Gdk::Rectangle (0, 0, 0, 0));
824 /** Hackily arrange for the provided widget to have no tooltip,
825 * and also to stop any other widget from providing one while
826 * the mouse is over w.
829 Gtkmm2ext::set_no_tooltip_whatsoever (Gtk::Widget& w)
831 w.property_has_tooltip() = true;
832 w.signal_query_tooltip().connect (sigc::ptr_fun (make_null_tooltip));
836 Gtkmm2ext::enable_tooltips ()
838 gtk_rc_parse_string ("gtk-enable-tooltips = 1");
842 Gtkmm2ext::disable_tooltips ()
844 gtk_rc_parse_string ("gtk-enable-tooltips = 0");
848 Gtkmm2ext::event_inside_widget_window (Gtk::Widget& widget, GdkEvent* ev)
852 if (!gdk_event_get_root_coords (ev, &evx, &evy)) {
858 gint width, height, depth;
861 Glib::RefPtr<Gdk::Window> widget_window = widget.get_window();
863 widget_window->get_geometry (x, y, width, height, depth);
864 widget_window->get_root_origin (wx, wy);
866 if ((evx >= wx && evx < wx + width) &&
867 (evy >= wy && evy < wy + height)) {
875 Gtkmm2ext::event_type_string (int event_type)
877 switch (event_type) {
886 case GDK_MOTION_NOTIFY:
887 return "motion_notify";
888 case GDK_BUTTON_PRESS:
889 return "button_press";
890 case GDK_2BUTTON_PRESS:
891 return "2button_press";
892 case GDK_3BUTTON_PRESS:
893 return "3button_press";
894 case GDK_BUTTON_RELEASE:
895 return "button_release";
898 case GDK_KEY_RELEASE:
899 return "key_release";
900 case GDK_ENTER_NOTIFY:
901 return "enter_notify";
902 case GDK_LEAVE_NOTIFY:
903 return "leave_notify";
904 case GDK_FOCUS_CHANGE:
905 return "focus_change";
912 case GDK_PROPERTY_NOTIFY:
913 return "property_notify";
914 case GDK_SELECTION_CLEAR:
915 return "selection_clear";
916 case GDK_SELECTION_REQUEST:
917 return "selection_request";
918 case GDK_SELECTION_NOTIFY:
919 return "selection_notify";
920 case GDK_PROXIMITY_IN:
921 return "proximity_in";
922 case GDK_PROXIMITY_OUT:
923 return "proximity_out";
928 case GDK_DRAG_MOTION:
929 return "drag_motion";
930 case GDK_DRAG_STATUS:
931 return "drag_status";
934 case GDK_DROP_FINISHED:
935 return "drop_finished";
936 case GDK_CLIENT_EVENT:
937 return "client_event";
938 case GDK_VISIBILITY_NOTIFY:
939 return "visibility_notify";
944 case GDK_WINDOW_STATE:
945 return "window_state";
948 case GDK_OWNER_CHANGE:
949 return "owner_change";
950 case GDK_GRAB_BROKEN:
951 return "grab_broken";
960 Gtkmm2ext::markup_escape_text (std::string const& s)
962 return Glib::Markup::escape_text (s);
966 Gtkmm2ext::add_volume_shortcuts (Gtk::FileChooser& c)
970 /* This is a first order approach, listing all mounted volumes (incl network).
971 * One could use `diskutil` or `mount` to query local disks only, or
972 * something even fancier if deemed appropriate.
974 Glib::Dir dir("/Volumes");
975 for (Glib::DirIterator di = dir.begin(); di != dir.end(); di++) {
976 string fullpath = Glib::build_filename ("/Volumes", *di);
977 if (!Glib::file_test (fullpath, Glib::FILE_TEST_IS_DIR)) continue;
979 try { /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
980 c.add_shortcut_folder (fullpath);
982 catch (Glib::Error& e) {
983 std::cerr << "add_shortcut_folder() threw Glib::Error: " << e.what() << std::endl;
987 catch (Glib::FileError& e) {
988 std::cerr << "listing /Volumnes failed: " << e.what() << std::endl;