Zoom session when the mouse pointer is moved up and down during a playhead drag.
[ardour2.git] / gtk2_ardour / utils.cc
blob8cdf5e0b58650b3a04083b6d97308c2146e8da19
1 /*
2 Copyright (C) 2003 Paul Davis
4 This program is free software; you an redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
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.
20 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
24 #include <pango/pangoft2.h> // for fontmap resolution control for GnomeCanvas
25 #include <pango/pangocairo.h> // for fontmap resolution control for GnomeCanvas
27 #include <cstdlib>
28 #include <cctype>
29 #include <fstream>
30 #include <sys/stat.h>
31 #include <libart_lgpl/art_misc.h>
32 #include <gtkmm/rc.h>
33 #include <gtkmm/window.h>
34 #include <gtkmm/combo.h>
35 #include <gtkmm/label.h>
36 #include <gtkmm/paned.h>
37 #include <gtk/gtkpaned.h>
39 #include "pbd/file_utils.h"
41 #include <gtkmm2ext/utils.h>
42 #include "ardour/configuration.h"
43 #include "ardour/rc_configuration.h"
45 #include "ardour/filesystem_paths.h"
47 #include "ardour_ui.h"
48 #include "debug.h"
49 #include "public_editor.h"
50 #include "keyboard.h"
51 #include "utils.h"
52 #include "i18n.h"
53 #include "rgb_macros.h"
54 #include "canvas_impl.h"
55 #include "gui_thread.h"
57 using namespace std;
58 using namespace Gtk;
59 using namespace Glib;
60 using namespace PBD;
61 using Gtkmm2ext::Keyboard;
63 sigc::signal<void> DPIReset;
65 int
66 pixel_width (const string& str, Pango::FontDescription& font)
68 Label foo;
69 Glib::RefPtr<Pango::Layout> layout = foo.create_pango_layout ("");
71 layout->set_font_description (font);
72 layout->set_text (str);
74 int width, height;
75 Gtkmm2ext::get_ink_pixel_size (layout, width, height);
76 return width;
79 string
80 fit_to_pixels (const string& str, int pixel_width, Pango::FontDescription& font, int& actual_width, bool with_ellipses)
82 Label foo;
83 Glib::RefPtr<Pango::Layout> layout = foo.create_pango_layout ("");
84 string::size_type shorter_by = 0;
85 string txt;
87 layout->set_font_description (font);
89 actual_width = 0;
91 string ustr = str;
92 string::iterator last = ustr.end();
93 --last; /* now points at final entry */
95 txt = ustr;
97 while (!ustr.empty()) {
99 layout->set_text (txt);
101 int width, height;
102 Gtkmm2ext::get_ink_pixel_size (layout, width, height);
104 if (width < pixel_width) {
105 actual_width = width;
106 break;
109 ustr.erase (last--);
110 shorter_by++;
112 if (with_ellipses && shorter_by > 3) {
113 txt = ustr;
114 txt += "...";
115 } else {
116 txt = ustr;
120 return txt;
123 /** Try to fit a string into a given horizontal space by ellipsizing it.
124 * @param cr Cairo context in which the text will be plotted.
125 * @param name Text.
126 * @param avail Available horizontal space.
127 * @return (Text, possibly ellipsized) and (horizontal size of text)
130 std::pair<std::string, double>
131 fit_to_pixels (cairo_t* cr, std::string name, double avail)
133 /* XXX hopefully there exists a more efficient way of doing this */
135 bool abbreviated = false;
136 uint32_t width = 0;
138 while (1) {
139 cairo_text_extents_t ext;
140 cairo_text_extents (cr, name.c_str(), &ext);
142 if (ext.width < avail || name.length() <= 4) {
143 width = ext.width;
144 break;
147 if (abbreviated) {
148 name = name.substr (0, name.length() - 4) + "...";
149 } else {
150 name = name.substr (0, name.length() - 3) + "...";
151 abbreviated = true;
155 return std::make_pair (name, width);
159 /** Add an element to a menu, settings its sensitivity.
160 * @param m Menu to add to.
161 * @param e Element to add.
162 * @param s true to make sensitive, false to make insensitive
164 void
165 add_item_with_sensitivity (Menu_Helpers::MenuList& m, Menu_Helpers::MenuElem e, bool s)
167 m.push_back (e);
168 if (!s) {
169 m.back().set_sensitive (false);
174 gint
175 just_hide_it (GdkEventAny */*ev*/, Gtk::Window *win)
177 win->hide ();
178 return 0;
181 /* xpm2rgb copied from nixieclock, which bore the legend:
183 nixieclock - a nixie desktop timepiece
184 Copyright (C) 2000 Greg Ercolano, erco@3dsite.com
186 and was released under the GPL.
189 unsigned char*
190 xpm2rgb (const char** xpm, uint32_t& w, uint32_t& h)
192 static long vals[256], val;
193 uint32_t t, x, y, colors, cpp;
194 unsigned char c;
195 unsigned char *savergb, *rgb;
197 // PARSE HEADER
199 if ( sscanf(xpm[0], "%u%u%u%u", &w, &h, &colors, &cpp) != 4 ) {
200 error << string_compose (_("bad XPM header %1"), xpm[0])
201 << endmsg;
202 return 0;
205 savergb = rgb = (unsigned char*) malloc (h * w * 3);
207 // LOAD XPM COLORMAP LONG ENOUGH TO DO CONVERSION
208 for (t = 0; t < colors; ++t) {
209 sscanf (xpm[t+1], "%c c #%lx", &c, &val);
210 vals[c] = val;
213 // COLORMAP -> RGB CONVERSION
214 // Get low 3 bytes from vals[]
217 const char *p;
218 for (y = h-1; y > 0; --y) {
220 for (p = xpm[1+colors+(h-y-1)], x = 0; x < w; x++, rgb += 3) {
221 val = vals[(int)*p++];
222 *(rgb+2) = val & 0xff; val >>= 8; // 2:B
223 *(rgb+1) = val & 0xff; val >>= 8; // 1:G
224 *(rgb+0) = val & 0xff; // 0:R
228 return (savergb);
231 unsigned char*
232 xpm2rgba (const char** xpm, uint32_t& w, uint32_t& h)
234 static long vals[256], val;
235 uint32_t t, x, y, colors, cpp;
236 unsigned char c;
237 unsigned char *savergb, *rgb;
238 char transparent;
240 // PARSE HEADER
242 if ( sscanf(xpm[0], "%u%u%u%u", &w, &h, &colors, &cpp) != 4 ) {
243 error << string_compose (_("bad XPM header %1"), xpm[0])
244 << endmsg;
245 return 0;
248 savergb = rgb = (unsigned char*) malloc (h * w * 4);
250 // LOAD XPM COLORMAP LONG ENOUGH TO DO CONVERSION
252 if (strstr (xpm[1], "None")) {
253 sscanf (xpm[1], "%c", &transparent);
254 t = 1;
255 } else {
256 transparent = 0;
257 t = 0;
260 for (; t < colors; ++t) {
261 sscanf (xpm[t+1], "%c c #%lx", &c, &val);
262 vals[c] = val;
265 // COLORMAP -> RGB CONVERSION
266 // Get low 3 bytes from vals[]
269 const char *p;
270 for (y = h-1; y > 0; --y) {
272 char alpha;
274 for (p = xpm[1+colors+(h-y-1)], x = 0; x < w; x++, rgb += 4) {
276 if (transparent && (*p++ == transparent)) {
277 alpha = 0;
278 val = 0;
279 } else {
280 alpha = 255;
281 val = vals[(int)*p];
284 *(rgb+3) = alpha; // 3: alpha
285 *(rgb+2) = val & 0xff; val >>= 8; // 2:B
286 *(rgb+1) = val & 0xff; val >>= 8; // 1:G
287 *(rgb+0) = val & 0xff; // 0:R
291 return (savergb);
294 ArdourCanvas::Points*
295 get_canvas_points (string /*who*/, uint32_t npoints)
297 // cerr << who << ": wants " << npoints << " canvas points" << endl;
298 #ifdef TRAP_EXCESSIVE_POINT_REQUESTS
299 if (npoints > (uint32_t) gdk_screen_width() + 4) {
300 abort ();
302 #endif
303 return new ArdourCanvas::Points (npoints);
306 Pango::FontDescription*
307 get_font_for_style (string widgetname)
309 Gtk::Window window (WINDOW_TOPLEVEL);
310 Gtk::Label foobar;
311 Glib::RefPtr<Gtk::Style> style;
313 window.add (foobar);
314 foobar.set_name (widgetname);
315 foobar.ensure_style();
317 style = foobar.get_style ();
319 Glib::RefPtr<const Pango::Layout> layout = foobar.get_layout();
321 PangoFontDescription *pfd = (PangoFontDescription *)pango_layout_get_font_description((PangoLayout *)layout->gobj());
323 if (!pfd) {
325 /* layout inherited its font description from a PangoContext */
327 PangoContext* ctxt = (PangoContext*) pango_layout_get_context ((PangoLayout*) layout->gobj());
328 pfd = pango_context_get_font_description (ctxt);
329 return new Pango::FontDescription (pfd, true); /* make a copy */
332 return new Pango::FontDescription (pfd, true); /* make a copy */
335 uint32_t
336 rgba_from_style (string style, uint32_t r, uint32_t g, uint32_t b, uint32_t a, string attr, int state, bool rgba)
338 /* In GTK+2, styles aren't set up correctly if the widget is not
339 attached to a toplevel window that has a screen pointer.
342 static Gtk::Window* window = 0;
344 if (window == 0) {
345 window = new Window (WINDOW_TOPLEVEL);
348 Gtk::Label foo;
350 window->add (foo);
352 foo.set_name (style);
353 foo.ensure_style ();
355 GtkRcStyle* rc = foo.get_style()->gobj()->rc_style;
357 if (rc) {
358 if (attr == "fg") {
359 r = rc->fg[state].red / 257;
360 g = rc->fg[state].green / 257;
361 b = rc->fg[state].blue / 257;
363 /* what a hack ... "a" is for "active" */
364 if (state == Gtk::STATE_NORMAL && rgba) {
365 a = rc->fg[GTK_STATE_ACTIVE].red / 257;
367 } else if (attr == "bg") {
368 r = g = b = 0;
369 r = rc->bg[state].red / 257;
370 g = rc->bg[state].green / 257;
371 b = rc->bg[state].blue / 257;
372 } else if (attr == "base") {
373 r = rc->base[state].red / 257;
374 g = rc->base[state].green / 257;
375 b = rc->base[state].blue / 257;
376 } else if (attr == "text") {
377 r = rc->text[state].red / 257;
378 g = rc->text[state].green / 257;
379 b = rc->text[state].blue / 257;
381 } else {
382 warning << string_compose (_("missing RGBA style for \"%1\""), style) << endl;
385 window->remove ();
387 if (state == Gtk::STATE_NORMAL && rgba) {
388 return (uint32_t) RGBA_TO_UINT(r,g,b,a);
389 } else {
390 return (uint32_t) RGB_TO_UINT(r,g,b);
395 Gdk::Color
396 color_from_style (string widget_style_name, int state, string attr)
398 GtkStyle* style;
400 style = gtk_rc_get_style_by_paths (gtk_settings_get_default(),
401 widget_style_name.c_str(),
402 0, G_TYPE_NONE);
404 if (!style) {
405 error << string_compose (_("no style found for %1, using red"), style) << endmsg;
406 return Gdk::Color ("red");
409 if (attr == "fg") {
410 return Gdk::Color (&style->fg[state]);
413 if (attr == "bg") {
414 return Gdk::Color (&style->bg[state]);
417 if (attr == "light") {
418 return Gdk::Color (&style->light[state]);
421 if (attr == "dark") {
422 return Gdk::Color (&style->dark[state]);
425 if (attr == "mid") {
426 return Gdk::Color (&style->mid[state]);
429 if (attr == "text") {
430 return Gdk::Color (&style->text[state]);
433 if (attr == "base") {
434 return Gdk::Color (&style->base[state]);
437 if (attr == "text_aa") {
438 return Gdk::Color (&style->text_aa[state]);
441 error << string_compose (_("unknown style attribute %1 requested for color; using \"red\""), attr) << endmsg;
442 return Gdk::Color ("red");
445 Glib::RefPtr<Gdk::GC>
446 gc_from_style (string widget_style_name, int state, string attr)
448 GtkStyle* style;
450 style = gtk_rc_get_style_by_paths (gtk_settings_get_default(),
451 widget_style_name.c_str(),
452 0, G_TYPE_NONE);
454 if (!style) {
455 error << string_compose (_("no style found for %1, using red"), style) << endmsg;
456 Glib::RefPtr<Gdk::GC> ret = Gdk::GC::create();
457 ret->set_rgb_fg_color(Gdk::Color("red"));
458 return ret;
461 if (attr == "fg") {
462 return Glib::wrap(style->fg_gc[state]);
465 if (attr == "bg") {
466 return Glib::wrap(style->bg_gc[state]);
469 if (attr == "light") {
470 return Glib::wrap(style->light_gc[state]);
473 if (attr == "dark") {
474 return Glib::wrap(style->dark_gc[state]);
477 if (attr == "mid") {
478 return Glib::wrap(style->mid_gc[state]);
481 if (attr == "text") {
482 return Glib::wrap(style->text_gc[state]);
485 if (attr == "base") {
486 return Glib::wrap(style->base_gc[state]);
489 if (attr == "text_aa") {
490 return Glib::wrap(style->text_aa_gc[state]);
493 error << string_compose (_("unknown style attribute %1 requested for color; using \"red\""), attr) << endmsg;
494 Glib::RefPtr<Gdk::GC> ret = Gdk::GC::create();
495 ret->set_rgb_fg_color(Gdk::Color("red"));
496 return ret;
500 bool
501 canvas_item_visible (ArdourCanvas::Item* item)
503 return (item->gobj()->object.flags & GNOME_CANVAS_ITEM_VISIBLE) ? true : false;
506 void
507 set_color (Gdk::Color& c, int rgb)
509 c.set_rgb((rgb >> 16)*256, ((rgb & 0xff00) >> 8)*256, (rgb & 0xff)*256);
512 bool
513 relay_key_press (GdkEventKey* ev, Gtk::Window* win)
515 if (!key_press_focus_accelerator_handler (*win, ev)) {
516 return PublicEditor::instance().on_key_press_event(ev);
517 } else {
518 return true;
522 bool
523 forward_key_press (GdkEventKey* ev)
525 return PublicEditor::instance().on_key_press_event(ev);
528 #ifdef GTKOSX
529 static guint
530 osx_keyval_without_alt (guint accent_keyval)
532 switch (accent_keyval) {
533 case GDK_oe:
534 return GDK_q;
535 case GDK_registered:
536 return GDK_r;
537 case GDK_dagger:
538 return GDK_t;
539 case GDK_yen:
540 return GDK_y;
541 case GDK_diaeresis:
542 return GDK_u;
543 case GDK_oslash:
544 return GDK_o;
545 case GDK_Greek_pi:
546 return GDK_p;
547 case GDK_leftdoublequotemark:
548 return GDK_bracketleft;
549 case GDK_leftsinglequotemark:
550 return GDK_bracketright;
551 case GDK_guillemotleft:
552 return GDK_backslash;
553 case GDK_aring:
554 return GDK_a;
555 case GDK_ssharp:
556 return GDK_s;
557 case GDK_partialderivative:
558 return GDK_d;
559 case GDK_function:
560 return GDK_f;
561 case GDK_copyright:
562 return GDK_g;
563 case GDK_abovedot:
564 return GDK_h;
565 case GDK_notsign:
566 return GDK_l;
567 case GDK_ellipsis:
568 return GDK_semicolon;
569 case GDK_ae:
570 return GDK_apostrophe;
571 case GDK_Greek_OMEGA:
572 return GDK_z;
573 case GDK_ccedilla:
574 return GDK_c;
575 case GDK_radical:
576 return GDK_v;
577 case GDK_integral:
578 return GDK_b;
579 case GDK_mu:
580 return GDK_m;
581 case GDK_lessthanequal:
582 return GDK_comma;
583 case GDK_greaterthanequal:
584 return GDK_period;
585 case GDK_division:
586 return GDK_slash;
587 default:
588 break;
591 return GDK_VoidSymbol;
593 #endif
595 bool
596 key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev)
598 GtkWindow* win = window.gobj();
599 GtkWidget* focus = gtk_window_get_focus (win);
600 bool special_handling_of_unmodified_accelerators = false;
601 bool allow_activating = true;
603 if (focus) {
604 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
605 special_handling_of_unmodified_accelerators = true;
609 #ifdef GTKOSX
610 /* should this be universally true? */
611 if (Keyboard::some_magic_widget_has_focus ()) {
612 allow_activating = false;
614 #endif
617 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 Key event: code = %2 state = %3 special handling ? %4 magic widget focus ? %5 allow_activation ? %6\n",
618 win,
619 ev->keyval,
620 ev->state,
621 special_handling_of_unmodified_accelerators,
622 Keyboard::some_magic_widget_has_focus(),
623 allow_activating));
625 /* This exists to allow us to override the way GTK handles
626 key events. The normal sequence is:
628 a) event is delivered to a GtkWindow
629 b) accelerators/mnemonics are activated
630 c) if (b) didn't handle the event, propagate to
631 the focus widget and/or focus chain
633 The problem with this is that if the accelerators include
634 keys without modifiers, such as the space bar or the
635 letter "e", then pressing the key while typing into
636 a text entry widget results in the accelerator being
637 activated, instead of the desired letter appearing
638 in the text entry.
640 There is no good way of fixing this, but this
641 represents a compromise. The idea is that
642 key events involving modifiers (not Shift)
643 get routed into the activation pathway first, then
644 get propagated to the focus widget if necessary.
646 If the key event doesn't involve modifiers,
647 we deliver to the focus widget first, thus allowing
648 it to get "normal text" without interference
649 from acceleration.
651 Of course, this can also be problematic: if there
652 is a widget with focus, then it will swallow
653 all "normal text" accelerators.
656 #ifdef GTKOSX
657 if (!special_handling_of_unmodified_accelerators) {
658 if (ev->state & GDK_MOD1_MASK) {
659 /* we're not in a text entry or "magic focus" widget so we don't want OS X "special-character"
660 text-style handling of alt-<key>. change the keyval back to what it would be without
661 the alt key. this way, we see <alt>-v rather than <alt>-radical and so on.
663 guint keyval_without_alt = osx_keyval_without_alt (ev->keyval);
665 if (keyval_without_alt != GDK_VoidSymbol) {
666 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Remapped %1 to %2\n", gdk_keyval_name (ev->keyval), gdk_keyval_name (keyval_without_alt)));
667 ev->keyval = keyval_without_alt;
671 #endif
673 if (!special_handling_of_unmodified_accelerators) {
675 /* pretend that certain key events that GTK does not allow
676 to be used as accelerators are actually something that
677 it does allow.
680 uint32_t fakekey = ev->keyval;
682 if (Gtkmm2ext::possibly_translate_keyval_to_make_legal_accelerator (fakekey)) {
683 if (allow_activating && gtk_accel_groups_activate(G_OBJECT(win), fakekey, GdkModifierType(ev->state))) {
684 return true;
689 /* consider all relevant modifiers but not LOCK or SHIFT */
691 guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
693 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
695 /* no special handling or there are modifiers in effect: accelerate first */
697 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
699 if (allow_activating) {
700 if (gtk_window_activate_key (win, ev)) {
701 return true;
705 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
707 return gtk_window_propagate_key_event (win, ev);
710 /* no modifiers, propagate first */
712 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
714 if (!gtk_window_propagate_key_event (win, ev)) {
715 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
716 if (allow_activating) {
717 return gtk_window_activate_key (win, ev);
720 } else {
721 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
722 return true;
725 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
726 return true;
729 Glib::RefPtr<Gdk::Pixbuf>
730 get_xpm (std::string name)
732 if (!xpm_map[name]) {
734 SearchPath spath(ARDOUR::ardour_search_path());
735 spath += ARDOUR::system_data_search_path();
737 spath.add_subdirectory_to_paths("pixmaps");
739 sys::path data_file_path;
741 if(!find_file_in_search_path (spath, name, data_file_path)) {
742 fatal << string_compose (_("cannot find XPM file for %1"), name) << endmsg;
745 try {
746 xpm_map[name] = Gdk::Pixbuf::create_from_file (data_file_path.to_string());
747 } catch(const Glib::Error& e) {
748 warning << "Caught Glib::Error: " << e.what() << endmsg;
752 return xpm_map[name];
755 std::string
756 get_icon_path (const char* cname)
758 string name = cname;
759 name += X_(".png");
761 SearchPath spath(ARDOUR::ardour_search_path());
762 spath += ARDOUR::system_data_search_path();
764 spath.add_subdirectory_to_paths("icons");
766 sys::path data_file_path;
768 if (!find_file_in_search_path (spath, name, data_file_path)) {
769 fatal << string_compose (_("cannot find icon image for %1"), name) << endmsg;
772 return data_file_path.to_string();
775 Glib::RefPtr<Gdk::Pixbuf>
776 get_icon (const char* cname)
778 Glib::RefPtr<Gdk::Pixbuf> img;
779 try {
780 img = Gdk::Pixbuf::create_from_file (get_icon_path (cname));
781 } catch (const Gdk::PixbufError &e) {
782 cerr << "Caught PixbufError: " << e.what() << endl;
783 } catch (...) {
784 g_message("Caught ... ");
787 return img;
790 string
791 longest (vector<string>& strings)
793 if (strings.empty()) {
794 return string ("");
797 vector<string>::iterator longest = strings.begin();
798 string::size_type longest_length = (*longest).length();
800 vector<string>::iterator i = longest;
801 ++i;
803 while (i != strings.end()) {
805 string::size_type len = (*i).length();
807 if (len > longest_length) {
808 longest = i;
809 longest_length = len;
812 ++i;
815 return *longest;
818 bool
819 key_is_legal_for_numeric_entry (guint keyval)
821 switch (keyval) {
822 case GDK_minus:
823 case GDK_plus:
824 case GDK_period:
825 case GDK_comma:
826 case GDK_0:
827 case GDK_1:
828 case GDK_2:
829 case GDK_3:
830 case GDK_4:
831 case GDK_5:
832 case GDK_6:
833 case GDK_7:
834 case GDK_8:
835 case GDK_9:
836 case GDK_KP_Add:
837 case GDK_KP_Subtract:
838 case GDK_KP_Decimal:
839 case GDK_KP_0:
840 case GDK_KP_1:
841 case GDK_KP_2:
842 case GDK_KP_3:
843 case GDK_KP_4:
844 case GDK_KP_5:
845 case GDK_KP_6:
846 case GDK_KP_7:
847 case GDK_KP_8:
848 case GDK_KP_9:
849 case GDK_Return:
850 case GDK_BackSpace:
851 case GDK_Delete:
852 case GDK_KP_Enter:
853 case GDK_Home:
854 case GDK_End:
855 case GDK_Left:
856 case GDK_Right:
857 return true;
859 default:
860 break;
863 return false;
865 void
866 set_pango_fontsize ()
868 long val = ARDOUR::Config->get_font_scale();
870 /* FT2 rendering - used by GnomeCanvas, sigh */
872 pango_ft2_font_map_set_resolution ((PangoFT2FontMap*) pango_ft2_font_map_for_display(), val/1024, val/1024);
874 /* Cairo rendering, in case there is any */
876 pango_cairo_font_map_set_resolution ((PangoCairoFontMap*) pango_cairo_font_map_get_default(), val/1024);
879 void
880 reset_dpi ()
882 long val = ARDOUR::Config->get_font_scale();
883 set_pango_fontsize ();
884 /* Xft rendering */
886 gtk_settings_set_long_property (gtk_settings_get_default(),
887 "gtk-xft-dpi", val, "ardour");
888 DPIReset();//Emit Signal
891 void
892 resize_window_to_proportion_of_monitor (Gtk::Window* window, int max_width, int max_height)
894 Glib::RefPtr<Gdk::Screen> screen = window->get_screen ();
895 Gdk::Rectangle monitor_rect;
896 screen->get_monitor_geometry (0, monitor_rect);
898 int const w = std::min (int (monitor_rect.get_width() * 0.8), max_width);
899 int const h = std::min (int (monitor_rect.get_height() * 0.8), max_height);
901 window->resize (w, h);
905 /** Replace _ with __ in a string; for use with menu item text to make underscores displayed correctly */
906 string
907 escape_underscores (string const & s)
909 string o;
910 string::size_type const N = s.length ();
912 for (string::size_type i = 0; i < N; ++i) {
913 if (s[i] == '_') {
914 o += "__";
915 } else {
916 o += s[i];
920 return o;