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 Glib::RefPtr<Gdk::Pixbuf> buf = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, clip_width, clip_height);
277 cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, clip_width, clip_height);
278 cairo_t* cr = cairo_create (surface);
279 cairo_text_extents_t te;
281 cairo_set_source_rgba (cr, fg.get_red_p(), fg.get_green_p(), fg.get_blue_p(), 1.0);
282 cairo_select_font_face (cr, font.get_family().c_str(),
283 CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
284 cairo_set_font_size (cr, font.get_size() / Pango::SCALE);
285 cairo_text_extents (cr, name.c_str(), &te);
287 cairo_move_to (cr, 0.5, int (0.5 - te.height / 2 - te.y_bearing + clip_height / 2));
288 cairo_show_text (cr, name.c_str());
290 convert_bgra_to_rgba(cairo_image_surface_get_data (surface), buf->get_pixels(), clip_width, clip_height);
293 cairo_surface_destroy(surface);
299 Gtkmm2ext::set_popdown_strings (Gtk::ComboBoxText& cr, const vector<string>& strings)
301 vector<string>::const_iterator i;
305 for (i = strings.begin(); i != strings.end(); ++i) {
311 Gtkmm2ext::get_popdown_strings (Gtk::ComboBoxText& cr, std::vector<std::string>& strings)
314 Glib::RefPtr<const Gtk::TreeModel> m = cr.get_model();
318 for(Gtk::TreeModel::iterator i = m->children().begin(); i != m->children().end(); ++i) {
320 (*i)->get_value(0, txt);
321 strings.push_back (txt);
326 Gtkmm2ext::get_popdown_string_count (Gtk::ComboBoxText& cr)
328 Glib::RefPtr<const Gtk::TreeModel> m = cr.get_model();
332 return m->children().size();
336 Gtkmm2ext::contains_value (Gtk::ComboBoxText& cr, const std::string text)
338 std::vector<std::string> s;
339 get_popdown_strings (cr, s);
340 return (std::find (s.begin(), s.end(), text) != s.end());
344 Gtkmm2ext::set_active_text_if_present (Gtk::ComboBoxText& cr, const std::string text)
346 if (contains_value(cr, text)) {
347 cr.set_active_text (text);
354 Gtkmm2ext::get_paned_handle (Gtk::Paned& paned)
356 return GTK_PANED(paned.gobj())->handle;
360 Gtkmm2ext::set_decoration (Gtk::Window* win, Gdk::WMDecoration decor)
362 win->get_window()->set_decorations (decor);
365 void Gtkmm2ext::set_treeview_header_as_default_label(Gtk::TreeViewColumn* c)
367 gtk_tree_view_column_set_widget( c->gobj(), GTK_WIDGET(0) );
371 Gtkmm2ext::detach_menu (Gtk::Menu& menu)
373 /* its possible for a Gtk::Menu to have no gobj() because it has
374 not yet been instantiated. Catch this and provide a safe
378 if (menu.get_attach_widget()) {
385 Gtkmm2ext::possibly_translate_mod_to_make_legal_accelerator (GdkModifierType& mod)
388 /* GTK on OS X is currently (February 2012) setting both
389 the Meta and Mod2 bits in the event modifier state if
390 the Command key is down.
392 gtk_accel_groups_activate() does not invoke any of the logic
393 that gtk_window_activate_key() will that sorts out that stupid
394 state of affairs, and as a result it fails to find a match
395 for the key event and the current set of accelerators.
397 to fix this, if the meta bit is set, remove the mod2 bit
398 from the modifier. this assumes that our bindings use Primary
399 which will have set the meta bit in the accelerator entry.
401 if (mod & GDK_META_MASK) {
402 mod = GdkModifierType (mod & ~GDK_MOD2_MASK);
409 Gtkmm2ext::possibly_translate_keyval_to_make_legal_accelerator (uint32_t& keyval)
411 int fakekey = GDK_VoidSymbol;
415 case GDK_ISO_Left_Tab:
420 fakekey = GDK_uparrow;
424 fakekey = GDK_downarrow;
428 fakekey = GDK_rightarrow;
432 fakekey = GDK_leftarrow;
436 fakekey = GDK_3270_Enter;
447 if (fakekey != GDK_VoidSymbol) {
456 Gtkmm2ext::possibly_translate_legal_accelerator_to_real_key (uint32_t keyval)
491 Gtkmm2ext::physical_screen_height (Glib::RefPtr<Gdk::Window> win)
493 GdkScreen* scr = gdk_screen_get_default();
497 gint monitor = gdk_screen_get_monitor_at_window (scr, win->gobj());
498 gdk_screen_get_monitor_geometry (scr, monitor, &r);
501 return gdk_screen_get_height (scr);
506 Gtkmm2ext::physical_screen_width (Glib::RefPtr<Gdk::Window> win)
508 GdkScreen* scr = gdk_screen_get_default();
512 gint monitor = gdk_screen_get_monitor_at_window (scr, win->gobj());
513 gdk_screen_get_monitor_geometry (scr, monitor, &r);
516 return gdk_screen_get_width (scr);
521 Gtkmm2ext::container_clear (Gtk::Container& c)
523 list<Gtk::Widget*> children = c.get_children();
524 for (list<Gtk::Widget*>::iterator child = children.begin(); child != children.end(); ++child) {
530 Gtkmm2ext::rounded_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
532 rounded_rectangle (context->cobj(), x, y, w, h, r);
535 Gtkmm2ext::rounded_top_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
537 rounded_top_rectangle (context->cobj(), x, y, w, h, r);
540 Gtkmm2ext::rounded_top_left_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
542 rounded_top_left_rectangle (context->cobj(), x, y, w, h, r);
545 Gtkmm2ext::rounded_top_right_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
547 rounded_top_right_rectangle (context->cobj(), x, y, w, h, r);
550 Gtkmm2ext::rounded_top_half_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
552 rounded_top_half_rectangle (context->cobj(), x, y, w, h, r);
555 Gtkmm2ext::rounded_bottom_half_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
557 rounded_bottom_half_rectangle (context->cobj(), x, y, w, h, r);
561 Gtkmm2ext::rounded_left_half_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
563 rounded_left_half_rectangle (context->cobj(), x, y, w, h, r);
567 Gtkmm2ext::rounded_right_half_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
569 rounded_right_half_rectangle (context->cobj(), x, y, w, h, r);
573 Gtkmm2ext::rounded_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
575 double degrees = M_PI / 180.0;
577 cairo_new_sub_path (cr);
578 cairo_arc (cr, x + w - r, y + r, r, -90 * degrees, 0 * degrees); //tr
579 cairo_arc (cr, x + w - r, y + h - r, r, 0 * degrees, 90 * degrees); //br
580 cairo_arc (cr, x + r, y + h - r, r, 90 * degrees, 180 * degrees); //bl
581 cairo_arc (cr, x + r, y + r, r, 180 * degrees, 270 * degrees); //tl
582 cairo_close_path (cr);
586 Gtkmm2ext::rounded_left_half_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
588 double degrees = M_PI / 180.0;
590 cairo_new_sub_path (cr);
591 cairo_line_to (cr, x+w, y); // tr
592 cairo_line_to (cr, x+w, y + h); // br
593 cairo_arc (cr, x + r, y + h - r, r, 90 * degrees, 180 * degrees); //bl
594 cairo_arc (cr, x + r, y + r, r, 180 * degrees, 270 * degrees); //tl
595 cairo_close_path (cr);
599 Gtkmm2ext::rounded_right_half_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
601 double degrees = M_PI / 180.0;
603 cairo_new_sub_path (cr);
604 cairo_arc (cr, x + w - r, y + r, r, -90 * degrees, 0 * degrees); //tr
605 cairo_arc (cr, x + w - r, y + h - r, r, 0 * degrees, 90 * degrees); //br
606 cairo_line_to (cr, x, y + h); // bl
607 cairo_line_to (cr, x, y); // tl
608 cairo_close_path (cr);
612 Gtkmm2ext::rounded_top_half_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
614 double degrees = M_PI / 180.0;
616 cairo_new_sub_path (cr);
617 cairo_move_to (cr, x+w, y+h);
618 cairo_line_to (cr, x, y+h);
619 cairo_arc (cr, x + r, y + r, r, 180 * degrees, 270 * degrees); //tl
620 cairo_arc (cr, x + w - r, y + r, r, -90 * degrees, 0 * degrees); //tr
621 cairo_close_path (cr);
625 Gtkmm2ext::rounded_bottom_half_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
627 double degrees = M_PI / 180.0;
629 cairo_new_sub_path (cr);
630 cairo_move_to (cr, x, y);
631 cairo_line_to (cr, x+w, y);
632 cairo_arc (cr, x + w - r, y + h - r, r, 0 * degrees, 90 * degrees); //br
633 cairo_arc (cr, x + r, y + h - r, r, 90 * degrees, 180 * degrees); //bl
634 cairo_close_path (cr);
639 Gtkmm2ext::rounded_top_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
641 double degrees = M_PI / 180.0;
643 cairo_new_sub_path (cr);
644 cairo_move_to (cr, x+w, y+h);
645 cairo_line_to (cr, x, y+h);
646 cairo_arc (cr, x + r, y + r, r, 180 * degrees, 270 * degrees); //tl
647 cairo_arc (cr, x + w - r, y + r, r, -90 * degrees, 0 * degrees); //tr
648 cairo_close_path (cr);
652 Gtkmm2ext::rounded_top_left_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
660 cairo_move_to (cr, x+r,y); // Move to A
661 cairo_line_to (cr, x+w,y); // Straight line to B
662 cairo_line_to (cr, x+w,y+h); // Move to E
663 cairo_line_to (cr, x,y+h); // Line to F
664 cairo_line_to (cr, x,y+r); // Line to H
665 cairo_curve_to (cr, x,y,x,y,x+r,y); // Curve to A
669 Gtkmm2ext::rounded_top_right_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
677 cairo_move_to (cr, x,y); // Move to A
678 cairo_line_to (cr, x+w-r,y); // Straight line to B
679 cairo_curve_to (cr, x+w,y,x+w,y,x+w,y+r); // Curve to C, Control points are both at Q
680 cairo_line_to (cr, x+w,y+h); // Move to E
681 cairo_line_to (cr, x,y+h); // Line to F
682 cairo_line_to (cr, x,y); // Line to A
685 Glib::RefPtr<Gdk::Window>
686 Gtkmm2ext::window_to_draw_on (Gtk::Widget& w, Gtk::Widget** parent)
688 if (w.get_has_window()) {
689 return w.get_window();
692 (*parent) = w.get_parent();
695 if ((*parent)->get_has_window()) {
696 return (*parent)->get_window ();
698 (*parent) = (*parent)->get_parent ();
701 return Glib::RefPtr<Gdk::Window> ();
705 Gtkmm2ext::pixel_width (const string& str, Pango::FontDescription& font)
707 Glib::RefPtr<Pango::Context> context = Glib::wrap (gdk_pango_context_get());
708 Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create (context);
710 layout->set_font_description (font);
711 layout->set_text (str);
714 Gtkmm2ext::get_ink_pixel_size (layout, width, height);
717 // Pango returns incorrect text width on some OS X
718 // So we have to make a correction
719 // To determine the correct indent take the largest symbol for which the width is correct
720 // and make the calculation
722 // see also libs/canvas/text.cc
724 layout->set_text ("H");
725 layout->get_pixel_size (cor_width, height);
726 width += cor_width * 1.5;
733 Gtkmm2ext::pixel_size (const string& str, Pango::FontDescription& font, int& width, int& height)
736 Glib::RefPtr<Pango::Layout> layout = foo.create_pango_layout ("");
738 layout->set_font_description (font);
739 layout->set_text (str);
741 Gtkmm2ext::get_ink_pixel_size (layout, width, height);
746 Gtkmm2ext::fit_to_pixels (const string& str, int pixel_width, Pango::FontDescription& font, int& actual_width, bool with_ellipses)
748 /* DECEMBER 2011: THIS PROTOTYPE OF fit_to_pixels() IS NOT USED
749 ANYWHERE AND HAS NOT BEEN TESTED.
752 Glib::RefPtr<Pango::Layout> layout = foo.create_pango_layout (str);
753 Glib::RefPtr<const Pango::LayoutLine> line;
755 layout->set_font_description (font);
756 layout->set_width (pixel_width * PANGO_SCALE);
759 layout->set_ellipsize (Pango::ELLIPSIZE_END);
761 layout->set_wrap (Pango::WRAP_CHAR);
764 line = layout->get_line (0);
766 /* XXX: might need special care to get the ellipsis character, not sure
770 string s = string (layout->get_text ().substr(line->get_start_index(), line->get_length()));
772 cerr << "fit to pixels of " << str << " returns " << s << endl;
778 /** Try to fit a string into a given horizontal space by ellipsizing it.
779 * @param cr Cairo context in which the text will be plotted.
781 * @param avail Available horizontal space.
782 * @return (Text, possibly ellipsized) and (horizontal size of text)
785 std::pair<std::string, double>
786 Gtkmm2ext::fit_to_pixels (cairo_t* cr, std::string name, double avail)
788 /* XXX hopefully there exists a more efficient way of doing this */
790 bool abbreviated = false;
794 cairo_text_extents_t ext;
795 cairo_text_extents (cr, name.c_str(), &ext);
797 if (ext.width < avail || name.length() <= 4) {
803 name = name.substr (0, name.length() - 4) + "...";
805 name = name.substr (0, name.length() - 3) + "...";
810 return std::make_pair (name, width);
814 Gtkmm2ext::left_aligned_label (string const & t)
816 Gtk::Label* l = new Gtk::Label (t);
817 l->set_alignment (0, 0.5);
822 Gtkmm2ext::right_aligned_label (string const & t)
824 Gtk::Label* l = new Gtk::Label (t);
825 l->set_alignment (1, 0.5);
830 make_null_tooltip (int, int, bool, const Glib::RefPtr<Gtk::Tooltip>& t)
832 t->set_tip_area (Gdk::Rectangle (0, 0, 0, 0));
836 /** Hackily arrange for the provided widget to have no tooltip,
837 * and also to stop any other widget from providing one while
838 * the mouse is over w.
841 Gtkmm2ext::set_no_tooltip_whatsoever (Gtk::Widget& w)
843 w.property_has_tooltip() = true;
844 w.signal_query_tooltip().connect (sigc::ptr_fun (make_null_tooltip));
848 Gtkmm2ext::enable_tooltips ()
850 gtk_rc_parse_string ("gtk-enable-tooltips = 1");
854 Gtkmm2ext::disable_tooltips ()
856 gtk_rc_parse_string ("gtk-enable-tooltips = 0");
860 Gtkmm2ext::event_inside_widget_window (Gtk::Widget& widget, GdkEvent* ev)
864 if (!gdk_event_get_root_coords (ev, &evx, &evy)) {
870 gint width, height, depth;
873 Glib::RefPtr<Gdk::Window> widget_window = widget.get_window();
875 widget_window->get_geometry (x, y, width, height, depth);
876 widget_window->get_root_origin (wx, wy);
878 if ((evx >= wx && evx < wx + width) &&
879 (evy >= wy && evy < wy + height)) {
887 Gtkmm2ext::event_type_string (int event_type)
889 switch (event_type) {
898 case GDK_MOTION_NOTIFY:
899 return "motion_notify";
900 case GDK_BUTTON_PRESS:
901 return "button_press";
902 case GDK_2BUTTON_PRESS:
903 return "2button_press";
904 case GDK_3BUTTON_PRESS:
905 return "3button_press";
906 case GDK_BUTTON_RELEASE:
907 return "button_release";
910 case GDK_KEY_RELEASE:
911 return "key_release";
912 case GDK_ENTER_NOTIFY:
913 return "enter_notify";
914 case GDK_LEAVE_NOTIFY:
915 return "leave_notify";
916 case GDK_FOCUS_CHANGE:
917 return "focus_change";
924 case GDK_PROPERTY_NOTIFY:
925 return "property_notify";
926 case GDK_SELECTION_CLEAR:
927 return "selection_clear";
928 case GDK_SELECTION_REQUEST:
929 return "selection_request";
930 case GDK_SELECTION_NOTIFY:
931 return "selection_notify";
932 case GDK_PROXIMITY_IN:
933 return "proximity_in";
934 case GDK_PROXIMITY_OUT:
935 return "proximity_out";
940 case GDK_DRAG_MOTION:
941 return "drag_motion";
942 case GDK_DRAG_STATUS:
943 return "drag_status";
946 case GDK_DROP_FINISHED:
947 return "drop_finished";
948 case GDK_CLIENT_EVENT:
949 return "client_event";
950 case GDK_VISIBILITY_NOTIFY:
951 return "visibility_notify";
956 case GDK_WINDOW_STATE:
957 return "window_state";
960 case GDK_OWNER_CHANGE:
961 return "owner_change";
962 case GDK_GRAB_BROKEN:
963 return "grab_broken";
972 Gtkmm2ext::markup_escape_text (std::string const& s)
974 return Glib::Markup::escape_text (s);
978 Gtkmm2ext::add_volume_shortcuts (Gtk::FileChooser& c)
982 /* This is a first order approach, listing all mounted volumes (incl network).
983 * One could use `diskutil` or `mount` to query local disks only, or
984 * something even fancier if deemed appropriate.
986 Glib::Dir dir("/Volumes");
987 for (Glib::DirIterator di = dir.begin(); di != dir.end(); di++) {
988 string fullpath = Glib::build_filename ("/Volumes", *di);
989 if (!Glib::file_test (fullpath, Glib::FILE_TEST_IS_DIR)) continue;
991 try { /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
992 c.add_shortcut_folder (fullpath);
994 catch (Glib::Error& e) {
995 std::cerr << "add_shortcut_folder() threw Glib::Error: " << e.what() << std::endl;
999 catch (Glib::FileError& e) {
1000 std::cerr << "listing /Volumnes failed: " << e.what() << std::endl;