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"
36 #include "gtkmm2ext/persistent_tooltip.h"
43 Gtkmm2ext::init (const char* localedir)
46 (void) bindtextdomain(PACKAGE, localedir);
47 (void) bind_textdomain_codeset (PACKAGE, "UTF-8");
52 Gtkmm2ext::get_ink_pixel_size (Glib::RefPtr<Pango::Layout> layout,
56 Pango::Rectangle ink_rect = layout->get_ink_extents ();
58 width = PANGO_PIXELS(ink_rect.get_width());
59 height = PANGO_PIXELS(ink_rect.get_height());
63 Gtkmm2ext::get_pixel_size (Glib::RefPtr<Pango::Layout> layout,
67 layout->get_pixel_size (width, height);
71 Gtkmm2ext::set_size_request_to_display_given_text (Gtk::Widget &w, const gchar *text,
72 gint hpadding, gint vpadding)
77 get_pixel_size (w.create_pango_layout (text), width, height);
78 w.set_size_request(width + hpadding, height + vpadding);
81 /** Set width request to display given text, and height to display anything.
82 This is useful for setting many widgets to the same height for consistency. */
84 Gtkmm2ext::set_size_request_to_display_given_text_width (Gtk::Widget& w,
89 static const gchar* vtext = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
94 get_pixel_size (w.create_pango_layout (htext), hwidth, hheight);
97 get_pixel_size (w.create_pango_layout (vtext), vwidth, vheight);
99 w.set_size_request(hwidth + hpadding, vheight + vpadding);
103 Gtkmm2ext::set_height_request_to_display_any_text (Gtk::Widget& w, gint vpadding)
105 static const gchar* vtext = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
110 get_pixel_size (w.create_pango_layout (vtext), width, height);
112 w.set_size_request(-1, height + vpadding);
116 Gtkmm2ext::set_size_request_to_display_given_text (Gtk::Widget &w, std::string const & text,
117 gint hpadding, gint vpadding)
122 get_pixel_size (w.create_pango_layout (text), width, height);
123 w.set_size_request(width + hpadding, height + vpadding);
127 Gtkmm2ext::set_size_request_to_display_given_text (Gtk::Widget &w,
128 const std::vector<std::string>& strings,
129 gint hpadding, gint vpadding)
136 const vector<string>* to_use;
137 vector<string>::const_iterator i;
139 for (i = strings.begin(); i != strings.end(); ++i) {
140 if ((*i).find_first_of ("gy") != string::npos) {
141 /* contains a descender */
146 if (i == strings.end()) {
147 /* make a copy of the strings then add one that has a descender */
149 copy.push_back ("g");
155 for (vector<string>::const_iterator i = to_use->begin(); i != to_use->end(); ++i) {
156 get_pixel_size (w.create_pango_layout (*i), width, height);
157 width_max = max(width_max,width);
158 height_max = max(height_max, height);
161 w.set_size_request(width_max + hpadding, height_max + vpadding);
164 /** This version specifies horizontal padding in text to avoid assumptions
165 about font size. Should be used anywhere padding is used to avoid text,
168 Gtkmm2ext::set_size_request_to_display_given_text (Gtk::Widget& w,
169 const std::vector<std::string>& strings,
170 const std::string& hpadding,
177 for (vector<string>::const_iterator i = strings.begin(); i != strings.end(); ++i) {
179 get_pixel_size (w.create_pango_layout (*i), width, height);
180 width_max = max(width_max,width);
181 height_max = max(height_max, height);
186 get_pixel_size (w.create_pango_layout (hpadding), pad_width, pad_height);
188 w.set_size_request(width_max + pad_width, height_max + vpadding);
192 demultiply_alpha (guint8 src,
195 /* cairo pixel buffer data contains RGB values with the alpha
196 values premultiplied.
198 GdkPixbuf pixel buffer data contains RGB values without the
201 this removes the alpha component from the cairo version and
202 returns the GdkPixbuf version.
204 return alpha ? ((guint (src) << 8) - src) / alpha : 0;
208 Gtkmm2ext::convert_bgra_to_rgba (guint8 const* src,
213 guint8 const* src_pixel = src;
214 guint8* dst_pixel = dst;
216 /* cairo pixel data is endian-dependent ARGB with A in the most significant 8 bits,
217 with premultipled alpha values (see preceding function)
219 GdkPixbuf pixel data is non-endian-dependent RGBA with R in the lowest addressable
220 8 bits, and non-premultiplied alpha values.
222 convert from the cairo values to the GdkPixbuf ones.
225 for (int y = 0; y < height; y++) {
226 for (int x = 0; x < width; x++) {
227 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
228 /* Cairo [ B G R A ] is actually [ B G R A ] in memory SOURCE
230 Pixbuf [ R G B A ] is actually [ R G B A ] in memory DEST
232 dst_pixel[0] = demultiply_alpha (src_pixel[2],
233 src_pixel[3]); // R [0] <= [ 2 ]
234 dst_pixel[1] = demultiply_alpha (src_pixel[1],
235 src_pixel[3]); // G [1] <= [ 1 ]
236 dst_pixel[2] = demultiply_alpha (src_pixel[0],
237 src_pixel[3]); // B [2] <= [ 0 ]
238 dst_pixel[3] = src_pixel[3]; // alpha
240 #elif G_BYTE_ORDER == G_BIG_ENDIAN
241 /* Cairo [ B G R A ] is actually [ A R G B ] in memory SOURCE
243 Pixbuf [ R G B A ] is actually [ R G B A ] in memory DEST
245 dst_pixel[0] = demultiply_alpha (src_pixel[1],
246 src_pixel[0]); // R [0] <= [ 1 ]
247 dst_pixel[1] = demultiply_alpha (src_pixel[2],
248 src_pixel[0]); // G [1] <= [ 2 ]
249 dst_pixel[2] = demultiply_alpha (src_pixel[3],
250 src_pixel[0]); // B [2] <= [ 3 ]
251 dst_pixel[3] = src_pixel[0]; // alpha
254 #error ardour does not currently support PDP-endianess
263 Glib::RefPtr<Gdk::Pixbuf>
264 Gtkmm2ext::pixbuf_from_string(const string& name, const Pango::FontDescription& font, int clip_width, int clip_height, Gdk::Color fg)
266 static Glib::RefPtr<Gdk::Pixbuf>* empty_pixbuf = 0;
269 if (empty_pixbuf == 0) {
270 empty_pixbuf = new Glib::RefPtr<Gdk::Pixbuf>;
271 *empty_pixbuf = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, clip_width, clip_height);
273 return *empty_pixbuf;
276 if (clip_width <= 0 || clip_height <= 0) {
277 /* negative values mean padding around natural size */
279 pixel_size (name, font, width, height);
280 if (clip_width <= 0) {
281 clip_width = width - clip_width;
283 if (clip_height <= 0) {
284 clip_height = height - clip_height;
288 Glib::RefPtr<Gdk::Pixbuf> buf = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, clip_width, clip_height);
290 cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, clip_width, clip_height);
291 cairo_t* cr = cairo_create (surface);
292 cairo_text_extents_t te;
294 cairo_set_source_rgba (cr, fg.get_red_p(), fg.get_green_p(), fg.get_blue_p(), 1.0);
295 cairo_select_font_face (cr, font.get_family().c_str(),
296 CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
297 cairo_set_font_size (cr, font.get_size() / Pango::SCALE);
298 cairo_text_extents (cr, name.c_str(), &te);
300 cairo_move_to (cr, 0.5, int (0.5 - te.height / 2 - te.y_bearing + clip_height / 2));
301 cairo_show_text (cr, name.c_str());
303 convert_bgra_to_rgba(cairo_image_surface_get_data (surface), buf->get_pixels(), clip_width, clip_height);
306 cairo_surface_destroy(surface);
312 Gtkmm2ext::set_popdown_strings (Gtk::ComboBoxText& cr, const vector<string>& strings)
314 vector<string>::const_iterator i;
318 for (i = strings.begin(); i != strings.end(); ++i) {
324 Gtkmm2ext::get_popdown_strings (Gtk::ComboBoxText& cr, std::vector<std::string>& strings)
327 Glib::RefPtr<const Gtk::TreeModel> m = cr.get_model();
331 for(Gtk::TreeModel::iterator i = m->children().begin(); i != m->children().end(); ++i) {
333 (*i)->get_value(0, txt);
334 strings.push_back (txt);
339 Gtkmm2ext::get_popdown_string_count (Gtk::ComboBoxText& cr)
341 Glib::RefPtr<const Gtk::TreeModel> m = cr.get_model();
345 return m->children().size();
349 Gtkmm2ext::contains_value (Gtk::ComboBoxText& cr, const std::string text)
351 std::vector<std::string> s;
352 get_popdown_strings (cr, s);
353 return (std::find (s.begin(), s.end(), text) != s.end());
357 Gtkmm2ext::set_active_text_if_present (Gtk::ComboBoxText& cr, const std::string text)
359 if (contains_value(cr, text)) {
360 cr.set_active_text (text);
367 Gtkmm2ext::get_paned_handle (Gtk::Paned& paned)
369 return GTK_PANED(paned.gobj())->handle;
373 Gtkmm2ext::set_decoration (Gtk::Window* win, Gdk::WMDecoration decor)
375 win->get_window()->set_decorations (decor);
378 void Gtkmm2ext::set_treeview_header_as_default_label(Gtk::TreeViewColumn* c)
380 gtk_tree_view_column_set_widget( c->gobj(), GTK_WIDGET(0) );
384 Gtkmm2ext::detach_menu (Gtk::Menu& menu)
386 /* its possible for a Gtk::Menu to have no gobj() because it has
387 not yet been instantiated. Catch this and provide a safe
391 if (menu.get_attach_widget()) {
398 Gtkmm2ext::possibly_translate_keyval_to_make_legal_accelerator (uint32_t& keyval)
400 int fakekey = GDK_VoidSymbol;
404 case GDK_ISO_Left_Tab:
409 fakekey = GDK_uparrow;
413 fakekey = GDK_downarrow;
417 fakekey = GDK_rightarrow;
421 fakekey = GDK_leftarrow;
425 fakekey = GDK_3270_Enter;
436 if (fakekey != GDK_VoidSymbol) {
445 Gtkmm2ext::possibly_translate_legal_accelerator_to_real_key (uint32_t keyval)
480 Gtkmm2ext::physical_screen_height (Glib::RefPtr<Gdk::Window> win)
482 GdkScreen* scr = gdk_screen_get_default();
486 gint monitor = gdk_screen_get_monitor_at_window (scr, win->gobj());
487 gdk_screen_get_monitor_geometry (scr, monitor, &r);
490 return gdk_screen_get_height (scr);
495 Gtkmm2ext::physical_screen_width (Glib::RefPtr<Gdk::Window> win)
497 GdkScreen* scr = gdk_screen_get_default();
501 gint monitor = gdk_screen_get_monitor_at_window (scr, win->gobj());
502 gdk_screen_get_monitor_geometry (scr, monitor, &r);
505 return gdk_screen_get_width (scr);
510 Gtkmm2ext::container_clear (Gtk::Container& c)
512 list<Gtk::Widget*> children = c.get_children();
513 for (list<Gtk::Widget*>::iterator child = children.begin(); child != children.end(); ++child) {
519 Gtkmm2ext::rounded_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
521 rounded_rectangle (context->cobj(), x, y, w, h, r);
524 Gtkmm2ext::rounded_top_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
526 rounded_top_rectangle (context->cobj(), x, y, w, h, r);
529 Gtkmm2ext::rounded_top_left_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
531 rounded_top_left_rectangle (context->cobj(), x, y, w, h, r);
534 Gtkmm2ext::rounded_top_right_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
536 rounded_top_right_rectangle (context->cobj(), x, y, w, h, r);
539 Gtkmm2ext::rounded_top_half_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
541 rounded_top_half_rectangle (context->cobj(), x, y, w, h, r);
544 Gtkmm2ext::rounded_bottom_half_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
546 rounded_bottom_half_rectangle (context->cobj(), x, y, w, h, r);
550 Gtkmm2ext::rounded_left_half_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
552 rounded_left_half_rectangle (context->cobj(), x, y, w, h, r);
556 Gtkmm2ext::rounded_right_half_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
558 rounded_right_half_rectangle (context->cobj(), x, y, w, h, r);
562 Gtkmm2ext::rounded_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
564 double degrees = M_PI / 180.0;
566 cairo_new_sub_path (cr);
567 cairo_arc (cr, x + w - r, y + r, r, -90 * degrees, 0 * degrees); //tr
568 cairo_arc (cr, x + w - r, y + h - r, r, 0 * degrees, 90 * degrees); //br
569 cairo_arc (cr, x + r, y + h - r, r, 90 * degrees, 180 * degrees); //bl
570 cairo_arc (cr, x + r, y + r, r, 180 * degrees, 270 * degrees); //tl
571 cairo_close_path (cr);
575 Gtkmm2ext::rounded_left_half_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
577 double degrees = M_PI / 180.0;
579 cairo_new_sub_path (cr);
580 cairo_line_to (cr, x+w, y); // tr
581 cairo_line_to (cr, x+w, y + h); // br
582 cairo_arc (cr, x + r, y + h - r, r, 90 * degrees, 180 * degrees); //bl
583 cairo_arc (cr, x + r, y + r, r, 180 * degrees, 270 * degrees); //tl
584 cairo_close_path (cr);
588 Gtkmm2ext::rounded_right_half_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
590 double degrees = M_PI / 180.0;
592 cairo_new_sub_path (cr);
593 cairo_arc (cr, x + w - r, y + r, r, -90 * degrees, 0 * degrees); //tr
594 cairo_arc (cr, x + w - r, y + h - r, r, 0 * degrees, 90 * degrees); //br
595 cairo_line_to (cr, x, y + h); // bl
596 cairo_line_to (cr, x, y); // tl
597 cairo_close_path (cr);
601 Gtkmm2ext::rounded_top_half_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
603 double degrees = M_PI / 180.0;
605 cairo_new_sub_path (cr);
606 cairo_move_to (cr, x+w, y+h);
607 cairo_line_to (cr, x, y+h);
608 cairo_arc (cr, x + r, y + r, r, 180 * degrees, 270 * degrees); //tl
609 cairo_arc (cr, x + w - r, y + r, r, -90 * degrees, 0 * degrees); //tr
610 cairo_close_path (cr);
614 Gtkmm2ext::rounded_bottom_half_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
616 double degrees = M_PI / 180.0;
618 cairo_new_sub_path (cr);
619 cairo_move_to (cr, x, y);
620 cairo_line_to (cr, x+w, y);
621 cairo_arc (cr, x + w - r, y + h - r, r, 0 * degrees, 90 * degrees); //br
622 cairo_arc (cr, x + r, y + h - r, r, 90 * degrees, 180 * degrees); //bl
623 cairo_close_path (cr);
628 Gtkmm2ext::rounded_top_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
630 double degrees = M_PI / 180.0;
632 cairo_new_sub_path (cr);
633 cairo_move_to (cr, x+w, y+h);
634 cairo_line_to (cr, x, y+h);
635 cairo_arc (cr, x + r, y + r, r, 180 * degrees, 270 * degrees); //tl
636 cairo_arc (cr, x + w - r, y + r, r, -90 * degrees, 0 * degrees); //tr
637 cairo_close_path (cr);
641 Gtkmm2ext::rounded_top_left_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
649 cairo_move_to (cr, x+r,y); // Move to A
650 cairo_line_to (cr, x+w,y); // Straight line to B
651 cairo_line_to (cr, x+w,y+h); // Move to E
652 cairo_line_to (cr, x,y+h); // Line to F
653 cairo_line_to (cr, x,y+r); // Line to H
654 cairo_curve_to (cr, x,y,x,y,x+r,y); // Curve to A
658 Gtkmm2ext::rounded_top_right_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
666 cairo_move_to (cr, x,y); // Move to A
667 cairo_line_to (cr, x+w-r,y); // Straight line to B
668 cairo_curve_to (cr, x+w,y,x+w,y,x+w,y+r); // Curve to C, Control points are both at Q
669 cairo_line_to (cr, x+w,y+h); // Move to E
670 cairo_line_to (cr, x,y+h); // Line to F
671 cairo_line_to (cr, x,y); // Line to A
674 Glib::RefPtr<Gdk::Window>
675 Gtkmm2ext::window_to_draw_on (Gtk::Widget& w, Gtk::Widget** parent)
677 if (w.get_has_window()) {
678 return w.get_window();
681 (*parent) = w.get_parent();
684 if ((*parent)->get_has_window()) {
685 return (*parent)->get_window ();
687 (*parent) = (*parent)->get_parent ();
690 return Glib::RefPtr<Gdk::Window> ();
694 Gtkmm2ext::pixel_width (const string& str, const Pango::FontDescription& font)
696 Glib::RefPtr<Pango::Context> context = Glib::wrap (gdk_pango_context_get());
697 Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create (context);
699 layout->set_font_description (font);
700 layout->set_text (str);
703 Gtkmm2ext::get_ink_pixel_size (layout, width, height);
706 // Pango returns incorrect text width on some OS X
707 // So we have to make a correction
708 // To determine the correct indent take the largest symbol for which the width is correct
709 // and make the calculation
711 // see also libs/canvas/text.cc
713 layout->set_text ("H");
714 layout->get_pixel_size (cor_width, height);
715 width += cor_width * 1.5;
722 Gtkmm2ext::pixel_size (const string& str, const Pango::FontDescription& font, int& width, int& height)
725 Glib::RefPtr<Pango::Layout> layout = foo.create_pango_layout ("");
727 layout->set_font_description (font);
728 layout->set_text (str);
730 Gtkmm2ext::get_ink_pixel_size (layout, width, height);
735 Gtkmm2ext::fit_to_pixels (const string& str, int pixel_width, Pango::FontDescription& font, int& actual_width, bool with_ellipses)
737 /* DECEMBER 2011: THIS PROTOTYPE OF fit_to_pixels() IS NOT USED
738 ANYWHERE AND HAS NOT BEEN TESTED.
741 Glib::RefPtr<Pango::Layout> layout = foo.create_pango_layout (str);
742 Glib::RefPtr<const Pango::LayoutLine> line;
744 layout->set_font_description (font);
745 layout->set_width (pixel_width * PANGO_SCALE);
748 layout->set_ellipsize (Pango::ELLIPSIZE_END);
750 layout->set_wrap (Pango::WRAP_CHAR);
753 line = layout->get_line (0);
755 /* XXX: might need special care to get the ellipsis character, not sure
759 string s = string (layout->get_text ().substr(line->get_start_index(), line->get_length()));
761 cerr << "fit to pixels of " << str << " returns " << s << endl;
767 /** Try to fit a string into a given horizontal space by ellipsizing it.
768 * @param cr Cairo context in which the text will be plotted.
770 * @param avail Available horizontal space.
771 * @return (Text, possibly ellipsized) and (horizontal size of text)
774 std::pair<std::string, double>
775 Gtkmm2ext::fit_to_pixels (cairo_t* cr, std::string name, double avail)
777 /* XXX hopefully there exists a more efficient way of doing this */
779 bool abbreviated = false;
783 cairo_text_extents_t ext;
784 cairo_text_extents (cr, name.c_str(), &ext);
786 if (ext.width < avail || name.length() <= 4) {
792 name = name.substr (0, name.length() - 4) + "...";
794 name = name.substr (0, name.length() - 3) + "...";
799 return std::make_pair (name, width);
803 Gtkmm2ext::left_aligned_label (string const & t)
805 Gtk::Label* l = new Gtk::Label (t);
806 l->set_alignment (0, 0.5);
811 Gtkmm2ext::right_aligned_label (string const & t)
813 Gtk::Label* l = new Gtk::Label (t);
814 l->set_alignment (1, 0.5);
819 make_null_tooltip (int, int, bool, const Glib::RefPtr<Gtk::Tooltip>& t)
821 t->set_tip_area (Gdk::Rectangle (0, 0, 0, 0));
825 /** Hackily arrange for the provided widget to have no tooltip,
826 * and also to stop any other widget from providing one while
827 * the mouse is over w.
830 Gtkmm2ext::set_no_tooltip_whatsoever (Gtk::Widget& w)
832 w.property_has_tooltip() = true;
833 w.signal_query_tooltip().connect (sigc::ptr_fun (make_null_tooltip));
837 Gtkmm2ext::enable_tooltips ()
839 gtk_rc_parse_string ("gtk-enable-tooltips = 1");
840 PersistentTooltip::set_tooltips_enabled (true);
844 Gtkmm2ext::disable_tooltips ()
846 gtk_rc_parse_string ("gtk-enable-tooltips = 0");
847 PersistentTooltip::set_tooltips_enabled (false);
851 Gtkmm2ext::event_inside_widget_window (Gtk::Widget& widget, GdkEvent* ev)
855 if (!gdk_event_get_root_coords (ev, &evx, &evy)) {
861 gint width, height, depth;
864 Glib::RefPtr<Gdk::Window> widget_window = widget.get_window();
866 widget_window->get_geometry (x, y, width, height, depth);
867 widget_window->get_root_origin (wx, wy);
869 if ((evx >= wx && evx < wx + width) &&
870 (evy >= wy && evy < wy + height)) {
878 Gtkmm2ext::event_type_string (int event_type)
880 switch (event_type) {
889 case GDK_MOTION_NOTIFY:
890 return "motion_notify";
891 case GDK_BUTTON_PRESS:
892 return "button_press";
893 case GDK_2BUTTON_PRESS:
894 return "2button_press";
895 case GDK_3BUTTON_PRESS:
896 return "3button_press";
897 case GDK_BUTTON_RELEASE:
898 return "button_release";
901 case GDK_KEY_RELEASE:
902 return "key_release";
903 case GDK_ENTER_NOTIFY:
904 return "enter_notify";
905 case GDK_LEAVE_NOTIFY:
906 return "leave_notify";
907 case GDK_FOCUS_CHANGE:
908 return "focus_change";
915 case GDK_PROPERTY_NOTIFY:
916 return "property_notify";
917 case GDK_SELECTION_CLEAR:
918 return "selection_clear";
919 case GDK_SELECTION_REQUEST:
920 return "selection_request";
921 case GDK_SELECTION_NOTIFY:
922 return "selection_notify";
923 case GDK_PROXIMITY_IN:
924 return "proximity_in";
925 case GDK_PROXIMITY_OUT:
926 return "proximity_out";
931 case GDK_DRAG_MOTION:
932 return "drag_motion";
933 case GDK_DRAG_STATUS:
934 return "drag_status";
937 case GDK_DROP_FINISHED:
938 return "drop_finished";
939 case GDK_CLIENT_EVENT:
940 return "client_event";
941 case GDK_VISIBILITY_NOTIFY:
942 return "visibility_notify";
947 case GDK_WINDOW_STATE:
948 return "window_state";
951 case GDK_OWNER_CHANGE:
952 return "owner_change";
953 case GDK_GRAB_BROKEN:
954 return "grab_broken";
963 Gtkmm2ext::markup_escape_text (std::string const& s)
965 return Glib::Markup::escape_text (s);
969 Gtkmm2ext::add_volume_shortcuts (Gtk::FileChooser& c)
973 /* This is a first order approach, listing all mounted volumes (incl network).
974 * One could use `diskutil` or `mount` to query local disks only, or
975 * something even fancier if deemed appropriate.
977 Glib::Dir dir("/Volumes");
978 for (Glib::DirIterator di = dir.begin(); di != dir.end(); di++) {
979 string fullpath = Glib::build_filename ("/Volumes", *di);
980 if (!Glib::file_test (fullpath, Glib::FILE_TEST_IS_DIR)) continue;
982 try { /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
983 c.add_shortcut_folder (fullpath);
985 catch (Glib::Error& e) {
986 std::cerr << "add_shortcut_folder() threw Glib::Error: " << e.what() << std::endl;
990 catch (Glib::FileError& e) {
991 std::cerr << "listing /Volumnes failed: " << e.what() << std::endl;
997 Gtkmm2ext::paned_position_as_fraction (Gtk::Paned& paned, bool h)
999 const guint pos = gtk_paned_get_position (const_cast<GtkPaned*>(static_cast<const Gtk::Paned*>(&paned)->gobj()));
1000 return (double) pos / (h ? paned.get_allocation().get_height() : paned.get_allocation().get_width());
1004 Gtkmm2ext::paned_set_position_as_fraction (Gtk::Paned& paned, float fraction, bool h)
1006 gint v = (h ? paned.get_allocation().get_height() : paned.get_allocation().get_width());
1012 paned.set_position ((guint) floor (fraction * v));