make marker labels and regionview name text (now drawn with pixbufs) be color-adjusta...
[ardour2.git] / gtk2_ardour / utils.cc
blob854b5f7862675e4a440e7db51ef5f2322d1b2818
1 /*
2 Copyright (C) 2003 Paul 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.
20 #include <pango/pangoft2.h> // for fontmap resolution control for GnomeCanvas
21 #include <pango/pangocairo.h> // for fontmap resolution control for GnomeCanvas
23 #include <cstdlib>
24 #include <cctype>
25 #include <fstream>
26 #include <sys/stat.h>
27 #include <libart_lgpl/art_misc.h>
28 #include <gtkmm/rc.h>
29 #include <gtkmm/window.h>
30 #include <gtkmm/combo.h>
31 #include <gtkmm/label.h>
32 #include <gtkmm/paned.h>
33 #include <gtk/gtkpaned.h>
35 #include <gtkmm2ext/utils.h>
36 #include <ardour/ardour.h>
37 #include <ardour/configuration.h>
39 #include "ardour_ui.h"
40 #include "keyboard.h"
41 #include "utils.h"
42 #include "i18n.h"
43 #include "rgb_macros.h"
44 #include "canvas_impl.h"
46 using namespace std;
47 using namespace Gtk;
48 using namespace sigc;
49 using namespace Glib;
50 using namespace PBD;
52 sigc::signal<void> DPIReset;
54 int
55 pixel_width (const ustring& str, Pango::FontDescription& font)
57 if (str.empty()) {
58 return 0;
61 Label foo;
62 Glib::RefPtr<Pango::Layout> layout = foo.create_pango_layout ("");
64 layout->set_font_description (font);
65 layout->set_text (str);
67 int width, height;
68 Gtkmm2ext::get_ink_pixel_size (layout, width, height);
69 return width;
72 ustring
73 fit_to_pixels (const ustring& str, int pixel_width, Pango::FontDescription& font, int& actual_width, bool with_ellipses)
75 Label foo;
76 Glib::RefPtr<Pango::Layout> layout = foo.create_pango_layout ("");
77 ustring::size_type shorter_by = 0;
78 ustring txt;
80 layout->set_font_description (font);
82 actual_width = 0;
84 ustring ustr = str;
85 ustring::iterator last = ustr.end();
86 --last; /* now points at final entry */
88 txt = ustr;
90 while (!ustr.empty()) {
92 layout->set_text (txt);
94 int width, height;
95 Gtkmm2ext::get_ink_pixel_size (layout, width, height);
97 if (width < pixel_width) {
98 actual_width = width;
99 break;
102 ustr.erase (last--);
103 shorter_by++;
105 if (with_ellipses && shorter_by > 3) {
106 txt = ustr;
107 txt += "...";
108 } else {
109 txt = ustr;
113 return txt;
116 gint
117 just_hide_it (GdkEventAny *ev, Gtk::Window *win)
119 win->hide ();
120 return TRUE;
123 /* xpm2rgb copied from nixieclock, which bore the legend:
125 nixieclock - a nixie desktop timepiece
126 Copyright (C) 2000 Greg Ercolano, erco@3dsite.com
128 and was released under the GPL.
131 unsigned char*
132 xpm2rgb (const char** xpm, uint32_t& w, uint32_t& h)
134 static long vals[256], val;
135 uint32_t t, x, y, colors, cpp;
136 unsigned char c;
137 unsigned char *savergb, *rgb;
139 // PARSE HEADER
141 if ( sscanf(xpm[0], "%u%u%u%u", &w, &h, &colors, &cpp) != 4 ) {
142 error << string_compose (_("bad XPM header %1"), xpm[0])
143 << endmsg;
144 return 0;
147 savergb = rgb = (unsigned char*) malloc (h * w * 3);
149 // LOAD XPM COLORMAP LONG ENOUGH TO DO CONVERSION
150 for (t = 0; t < colors; ++t) {
151 sscanf (xpm[t+1], "%c c #%lx", &c, &val);
152 vals[c] = val;
155 // COLORMAP -> RGB CONVERSION
156 // Get low 3 bytes from vals[]
159 const char *p;
160 for (y = h-1; y > 0; --y) {
162 for (p = xpm[1+colors+(h-y-1)], x = 0; x < w; x++, rgb += 3) {
163 val = vals[(int)*p++];
164 *(rgb+2) = val & 0xff; val >>= 8; // 2:B
165 *(rgb+1) = val & 0xff; val >>= 8; // 1:G
166 *(rgb+0) = val & 0xff; // 0:R
170 return (savergb);
173 unsigned char*
174 xpm2rgba (const char** xpm, uint32_t& w, uint32_t& h)
176 static long vals[256], val;
177 uint32_t t, x, y, colors, cpp;
178 unsigned char c;
179 unsigned char *savergb, *rgb;
180 char transparent;
182 // PARSE HEADER
184 if ( sscanf(xpm[0], "%u%u%u%u", &w, &h, &colors, &cpp) != 4 ) {
185 error << string_compose (_("bad XPM header %1"), xpm[0])
186 << endmsg;
187 return 0;
190 savergb = rgb = (unsigned char*) malloc (h * w * 4);
192 // LOAD XPM COLORMAP LONG ENOUGH TO DO CONVERSION
194 if (strstr (xpm[1], "None")) {
195 sscanf (xpm[1], "%c", &transparent);
196 t = 1;
197 } else {
198 transparent = 0;
199 t = 0;
202 for (; t < colors; ++t) {
203 sscanf (xpm[t+1], "%c c #%lx", &c, &val);
204 vals[c] = val;
207 // COLORMAP -> RGB CONVERSION
208 // Get low 3 bytes from vals[]
211 const char *p;
212 for (y = h-1; y > 0; --y) {
214 char alpha;
216 for (p = xpm[1+colors+(h-y-1)], x = 0; x < w; x++, rgb += 4) {
218 if (transparent && (*p++ == transparent)) {
219 alpha = 0;
220 val = 0;
221 } else {
222 alpha = 255;
223 val = vals[(int)*p];
226 *(rgb+3) = alpha; // 3: alpha
227 *(rgb+2) = val & 0xff; val >>= 8; // 2:B
228 *(rgb+1) = val & 0xff; val >>= 8; // 1:G
229 *(rgb+0) = val & 0xff; // 0:R
233 return (savergb);
236 ArdourCanvas::Points*
237 get_canvas_points (string who, uint32_t npoints)
239 // cerr << who << ": wants " << npoints << " canvas points" << endl;
240 #ifdef TRAP_EXCESSIVE_POINT_REQUESTS
241 if (npoints > (uint32_t) gdk_screen_width() + 4) {
242 abort ();
244 #endif
245 return new ArdourCanvas::Points (npoints);
248 Pango::FontDescription*
249 get_font_for_style (string widgetname)
251 Gtk::Window window (WINDOW_TOPLEVEL);
252 Gtk::Label foobar;
253 Glib::RefPtr<Gtk::Style> style;
255 window.add (foobar);
256 foobar.set_name (widgetname);
257 foobar.ensure_style();
259 style = foobar.get_style ();
261 Glib::RefPtr<const Pango::Layout> layout = foobar.get_layout();
263 PangoFontDescription *pfd = (PangoFontDescription *)pango_layout_get_font_description((PangoLayout *)layout->gobj());
265 if (!pfd) {
267 /* layout inherited its font description from a PangoContext */
269 PangoContext* ctxt = (PangoContext*) pango_layout_get_context ((PangoLayout*) layout->gobj());
270 pfd = pango_context_get_font_description (ctxt);
271 return new Pango::FontDescription (pfd, true); /* make a copy */
274 return new Pango::FontDescription (pfd, true); /* make a copy */
277 uint32_t
278 rgba_from_style (string style, uint32_t r, uint32_t g, uint32_t b, uint32_t a, string attr, int state, bool rgba)
280 /* In GTK+2, styles aren't set up correctly if the widget is not
281 attached to a toplevel window that has a screen pointer.
284 static Gtk::Window* window = 0;
286 if (window == 0) {
287 window = new Window (WINDOW_TOPLEVEL);
290 Gtk::Label foo;
292 window->add (foo);
294 foo.set_name (style);
295 foo.ensure_style ();
297 GtkRcStyle* waverc = foo.get_style()->gobj()->rc_style;
299 if (waverc) {
300 if (attr == "fg") {
301 r = waverc->fg[state].red / 257;
302 g = waverc->fg[state].green / 257;
303 b = waverc->fg[state].blue / 257;
305 /* what a hack ... "a" is for "active" */
306 if (state == Gtk::STATE_NORMAL && rgba) {
307 a = waverc->fg[GTK_STATE_ACTIVE].red / 257;
309 } else if (attr == "bg") {
310 r = g = b = 0;
311 r = waverc->bg[state].red / 257;
312 g = waverc->bg[state].green / 257;
313 b = waverc->bg[state].blue / 257;
314 } else if (attr == "base") {
315 r = waverc->base[state].red / 257;
316 g = waverc->base[state].green / 257;
317 b = waverc->base[state].blue / 257;
318 } else if (attr == "text") {
319 r = waverc->text[state].red / 257;
320 g = waverc->text[state].green / 257;
321 b = waverc->text[state].blue / 257;
323 } else {
324 warning << string_compose (_("missing RGBA style for \"%1\""), style) << endl;
327 window->remove ();
329 if (state == Gtk::STATE_NORMAL && rgba) {
330 return (uint32_t) RGBA_TO_UINT(r,g,b,a);
331 } else {
332 return (uint32_t) RGB_TO_UINT(r,g,b);
337 Gdk::Color
338 color_from_style (string widget_style_name, int state, string attr)
340 GtkStyle* style;
342 style = gtk_rc_get_style_by_paths (gtk_settings_get_default(),
343 widget_style_name.c_str(),
344 0, G_TYPE_NONE);
346 if (!style) {
347 error << string_compose (_("no style found for %1, using red"), style) << endmsg;
348 return Gdk::Color ("red");
351 cerr << "got style for " << widget_style_name << endl;
353 if (attr == "fg") {
354 return Gdk::Color (&style->fg[state]);
357 if (attr == "bg") {
358 cerr << "returning color from bg\n";
359 return Gdk::Color (&style->bg[state]);
362 if (attr == "light") {
363 return Gdk::Color (&style->light[state]);
366 if (attr == "dark") {
367 return Gdk::Color (&style->dark[state]);
370 if (attr == "mid") {
371 return Gdk::Color (&style->mid[state]);
374 if (attr == "text") {
375 return Gdk::Color (&style->text[state]);
378 if (attr == "base") {
379 return Gdk::Color (&style->base[state]);
382 if (attr == "text_aa") {
383 return Gdk::Color (&style->text_aa[state]);
386 error << string_compose (_("unknown style attribute %1 requested for color; using \"red\""), attr) << endmsg;
387 return Gdk::Color ("red");
391 bool
392 canvas_item_visible (ArdourCanvas::Item* item)
394 return (item->gobj()->object.flags & GNOME_CANVAS_ITEM_VISIBLE) ? true : false;
397 void
398 set_color (Gdk::Color& c, int rgb)
400 c.set_rgb((rgb >> 16)*256, ((rgb & 0xff00) >> 8)*256, (rgb & 0xff)*256);
403 bool
404 relay_key_press (GdkEventKey* ev, Gtk::Window* win)
406 if (!key_press_focus_accelerator_handler (*win, ev)) {
407 return PublicEditor::instance().on_key_press_event(ev);
408 } else {
409 return true;
413 #ifdef GTKOSX
414 static guint
415 osx_keyval_without_alt (guint accent_keyval)
417 switch (accent_keyval) {
418 case GDK_oe:
419 return GDK_q;
420 case GDK_registered:
421 return GDK_r;
422 case GDK_dagger:
423 return GDK_t;
424 case GDK_yen:
425 return GDK_y;
426 case GDK_diaeresis:
427 return GDK_u;
428 case GDK_oslash:
429 return GDK_o;
430 case GDK_Greek_pi:
431 return GDK_p;
432 case GDK_leftdoublequotemark:
433 return GDK_bracketleft;
434 case GDK_leftsinglequotemark:
435 return GDK_bracketright;
436 case GDK_guillemotleft:
437 return GDK_backslash;
438 case GDK_aring:
439 return GDK_a;
440 case GDK_ssharp:
441 return GDK_s;
442 case GDK_partialderivative:
443 return GDK_d;
444 case GDK_function:
445 return GDK_f;
446 case GDK_copyright:
447 return GDK_g;
448 case GDK_abovedot:
449 return GDK_h;
450 case GDK_notsign:
451 return GDK_l;
452 case GDK_ellipsis:
453 return GDK_semicolon;
454 case GDK_ae:
455 return GDK_apostrophe;
456 case GDK_Greek_OMEGA:
457 return GDK_z;
458 case GDK_ccedilla:
459 return GDK_c;
460 case GDK_radical:
461 return GDK_v;
462 case GDK_integral:
463 return GDK_b;
464 case GDK_mu:
465 return GDK_m;
466 case GDK_lessthanequal:
467 return GDK_comma;
468 case GDK_greaterthanequal:
469 return GDK_period;
470 case GDK_division:
471 return GDK_slash;
472 default:
473 break;
476 return GDK_VoidSymbol;
478 #endif
480 bool
481 key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev)
483 GtkWindow* win = window.gobj();
484 GtkWidget* focus = gtk_window_get_focus (win);
485 bool special_handling_of_unmodified_accelerators = false;
486 bool allow_activating = true;
488 //#define DEBUG_ACCELERATOR_HANDLING
489 #ifdef DEBUG_ACCELERATOR_HANDLING
490 //bool debug = (getenv ("ARDOUR_DEBUG_ACCELERATOR_HANDLING") != 0);
491 bool debug=true;
492 #endif
493 if (focus) {
494 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
495 special_handling_of_unmodified_accelerators = true;
497 #ifdef DEBUG_ACCELERATOR_HANDLING
498 cerr << "Focus widget name " << gtk_widget_get_name(focus) << endl;
499 #endif
502 #ifdef GTKOSX
503 /* should this be universally true? */
504 if (Keyboard::some_magic_widget_has_focus ()) {
505 allow_activating = false;
507 #endif
509 #ifdef DEBUG_ACCELERATOR_HANDLING
510 if (debug) {
511 cerr << "Win = " << win << " Key event: code = " << ev->keyval << " name = " << gdk_keyval_name (ev->keyval) << " state = " << hex << ev->state << dec
512 << " ctrl " << ((ev->state & GDK_CONTROL_MASK) ? 1 : 0)
513 << " alt " << ((ev->state & GDK_MOD1_MASK) ? 1 : 0)
514 << " shift " << ((ev->state & GDK_SHIFT_MASK) ? 1 : 0)
515 << " cmd/meta " << ((ev->state & GDK_META_MASK) ? 1 : 0)
516 << " lock " << ((ev->state & GDK_LOCK_MASK) ? 1 : 0)
517 << " special handling ? "
518 << special_handling_of_unmodified_accelerators
519 << " magic widget focus ? "
520 << Keyboard::some_magic_widget_has_focus()
521 << " allow_activation ? "
522 << allow_activating
523 << endl;
525 #endif
527 /* This exists to allow us to override the way GTK handles
528 key events. The normal sequence is:
530 a) event is delivered to a GtkWindow
531 b) accelerators/mnemonics are activated
532 c) if (b) didn't handle the event, propagate to
533 the focus widget and/or focus chain
535 The problem with this is that if the accelerators include
536 keys without modifiers, such as the space bar or the
537 letter "e", then pressing the key while typing into
538 a text entry widget results in the accelerator being
539 activated, instead of the desired letter appearing
540 in the text entry.
542 There is no good way of fixing this, but this
543 represents a compromise. The idea is that
544 key events involving modifiers (not Shift)
545 get routed into the activation pathway first, then
546 get propagated to the focus widget if necessary.
548 If the key event doesn't involve modifiers,
549 we deliver to the focus widget first, thus allowing
550 it to get "normal text" without interference
551 from acceleration.
553 Of course, this can also be problematic: if there
554 is a widget with focus, then it will swallow
555 all "normal text" accelerators.
558 #ifdef GTKOSX
559 if (!special_handling_of_unmodified_accelerators) {
560 if (ev->state & GDK_MOD1_MASK) {
561 /* we're not in a text entry or "magic focus" widget so we don't want OS X "special-character"
562 text-style handling of alt-<key>. change the keyval back to what it would be without
563 the alt key. this way, we see <alt>-v rather than <alt>-radical and so on.
565 guint keyval_without_alt = osx_keyval_without_alt (ev->keyval);
567 if (keyval_without_alt != GDK_VoidSymbol) {
568 #ifdef DEBUG_ACCELERATOR_HANDLING
569 cerr << "Remapped " << gdk_keyval_name (ev->keyval) << " to " << gdk_keyval_name (keyval_without_alt) << endl;
571 #endif ev->keyval = keyval_without_alt;
575 #endif
577 if (!special_handling_of_unmodified_accelerators) {
579 /* pretend that certain key events that GTK does not allow
580 to be used as accelerators are actually something that
581 it does allow.
584 uint32_t fakekey = ev->keyval;
586 if (possibly_translate_keyval_to_make_legal_accelerator (fakekey)) {
587 #ifdef DEBUG_ACCELERATOR_HANDLING
588 if (debug) {
589 cerr << "\tactivate (was " << ev->keyval << " now " << fakekey << ") without special handling of unmodified accels\n";
591 #endif
592 if (allow_activating && gtk_accel_groups_activate(G_OBJECT(win), fakekey, GdkModifierType(ev->state))) {
593 #ifdef DEBUG_ACCELERATOR_HANDLING
594 if (debug) {
595 cerr << "\tactivation handled key\n";
597 #endif
598 return true;
603 /* consider all relevant modifiers but not LOCK or SHIFT */
605 guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
607 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
609 /* no special handling or there are modifiers in effect: accelerate first */
611 #ifdef DEBUG_ACCELERATOR_HANDLING
612 if (debug) {
613 cerr << "\tactivate, then propagate\n";
615 #endif
617 if (allow_activating) {
618 if (gtk_window_activate_key (win, ev)) {
619 #ifdef DEBUG_ACCELERATOR_HANDLING
620 if (debug) {
621 cerr << "\tactivation handled key " << ev->keyval << endl;
623 #endif
625 return true;
629 #ifdef DEBUG_ACCELERATOR_HANDLING
630 if (debug) {
631 cerr << "\tnot accelerated, now propagate\n";
633 #endif
634 return gtk_window_propagate_key_event (win, ev);
637 /* no modifiers, propagate first */
639 #ifdef DEBUG_ACCELERATOR_HANDLING
640 if (debug) {
641 cerr << "\tpropagate, then activate\n";
643 #endif
644 if (!gtk_window_propagate_key_event (win, ev)) {
645 #ifdef DEBUG_ACCELERATOR_HANDLING
646 if (debug) {
647 cerr << "\tpropagation didn't handle, so activate\n";
649 #endif
651 if (allow_activating) {
652 return gtk_window_activate_key (win, ev);
655 } else {
656 #ifdef DEBUG_ACCELERATOR_HANDLING
657 if (debug) {
658 cerr << "\thandled by propagate\n";
660 #endif
661 return true;
664 #ifdef DEBUG_ACCELERATOR_HANDLING
665 if (debug) {
666 cerr << "\tnot handled\n";
668 #endif
669 return true;
672 Glib::RefPtr<Gdk::Pixbuf>
673 get_xpm (std::string name)
675 //cerr << "xpm path = " << ARDOUR::find_data_file(name, "pixmaps") << endl;//DEBUG
676 if (!xpm_map[name]) {
677 try {
678 xpm_map[name] = Gdk::Pixbuf::create_from_file (ARDOUR::find_data_file(name, "pixmaps"));
680 catch(const Glib::Error& e) {
681 warning << "Caught Glib::Error: " << e.what() << endmsg;
685 return (xpm_map[name]);
688 Glib::RefPtr<Gdk::Pixbuf>
689 get_icon (const char* cname)
691 string name = cname;
692 name += X_(".png");
694 string path = ARDOUR::find_data_file (name, "icons");
696 if (path.empty()) {
697 fatal << string_compose (_("cannot find icon image for %1"), name) << endmsg;
698 /*NOTREACHED*/
701 Glib::RefPtr<Gdk::Pixbuf> img;
702 try {
703 img = Gdk::Pixbuf::create_from_file (path);
705 catch (const Gdk::PixbufError &e)
707 cerr << "Caught PixbufError: " << e.what() << endl;
709 catch (...)
711 g_message("Caught ... ");
714 return img;
717 string
718 longest (vector<string>& strings)
720 if (strings.empty()) {
721 return string ("");
724 vector<string>::iterator longest = strings.begin();
725 string::size_type longest_length = (*longest).length();
727 vector<string>::iterator i = longest;
728 ++i;
730 while (i != strings.end()) {
732 string::size_type len = (*i).length();
734 if (len > longest_length) {
735 longest = i;
736 longest_length = len;
739 ++i;
742 return *longest;
745 bool
746 key_is_legal_for_numeric_entry (guint keyval)
748 switch (keyval) {
749 case GDK_minus:
750 case GDK_plus:
751 case GDK_period:
752 case GDK_comma:
753 case GDK_0:
754 case GDK_1:
755 case GDK_2:
756 case GDK_3:
757 case GDK_4:
758 case GDK_5:
759 case GDK_6:
760 case GDK_7:
761 case GDK_8:
762 case GDK_9:
763 case GDK_KP_Add:
764 case GDK_KP_Subtract:
765 case GDK_KP_Decimal:
766 case GDK_KP_0:
767 case GDK_KP_1:
768 case GDK_KP_2:
769 case GDK_KP_3:
770 case GDK_KP_4:
771 case GDK_KP_5:
772 case GDK_KP_6:
773 case GDK_KP_7:
774 case GDK_KP_8:
775 case GDK_KP_9:
776 case GDK_Return:
777 case GDK_BackSpace:
778 case GDK_Delete:
779 case GDK_KP_Enter:
780 case GDK_Home:
781 case GDK_End:
782 case GDK_Left:
783 case GDK_Right:
784 return true;
786 default:
787 break;
790 return false;
792 void
793 set_pango_fontsize ()
795 long val = ARDOUR::Config->get_font_scale();
797 /* FT2 rendering - used by GnomeCanvas, sigh */
799 pango_ft2_font_map_set_resolution ((PangoFT2FontMap*) pango_ft2_font_map_for_display(), val/1024, val/1024);
801 /* Cairo rendering, in case there is any */
803 // pango_cairo_font_map_set_resolution ((PangoCairoFontMap*) pango_cairo_font_map_get_default(), val/1024);
806 void
807 reset_dpi ()
809 long val = ARDOUR::Config->get_font_scale();
810 set_pango_fontsize ();
811 /* Xft rendering */
813 gtk_settings_set_long_property (gtk_settings_get_default(),
814 "gtk-xft-dpi", val, "ardour");
815 DPIReset();//Emit Signal
818 bool
819 possibly_translate_keyval_to_make_legal_accelerator (uint32_t& keyval)
821 int fakekey = GDK_VoidSymbol;
823 switch (keyval) {
824 case GDK_Tab:
825 case GDK_ISO_Left_Tab:
826 fakekey = GDK_nabla;
827 break;
829 case GDK_Up:
830 fakekey = GDK_uparrow;
831 break;
833 case GDK_Down:
834 fakekey = GDK_downarrow;
835 break;
837 case GDK_Right:
838 fakekey = GDK_rightarrow;
839 break;
841 case GDK_Left:
842 fakekey = GDK_leftarrow;
843 break;
845 default:
846 break;
849 if (fakekey != GDK_VoidSymbol) {
850 keyval = fakekey;
851 return true;
854 return false;
857 inline guint8
858 convert_color_channel (guint8 src,
859 guint8 alpha)
861 return alpha ? ((guint (src) << 8) - src) / alpha : 0;
864 void
865 convert_bgra_to_rgba (guint8 const* src,
866 guint8* dst,
867 int width,
868 int height)
870 guint8 const* src_pixel = src;
871 guint8* dst_pixel = dst;
873 for (int y = 0; y < height; y++)
874 for (int x = 0; x < width; x++)
876 dst_pixel[0] = convert_color_channel (src_pixel[2],
877 src_pixel[3]);
878 dst_pixel[1] = convert_color_channel (src_pixel[1],
879 src_pixel[3]);
880 dst_pixel[2] = convert_color_channel (src_pixel[0],
881 src_pixel[3]);
882 dst_pixel[3] = src_pixel[3];
884 dst_pixel += 4;
885 src_pixel += 4;
889 Glib::RefPtr<Gdk::Pixbuf>
890 pixbuf_from_ustring(const ustring& name, Pango::FontDescription* font, uint32_t rgba, int clip_width, int clip_height)
892 Glib::RefPtr<Gdk::Pixbuf> buf = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, clip_width, clip_height);
893 cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, clip_width, clip_height);
894 cairo_t* cr = cairo_create (surface);
895 cairo_text_extents_t te;
897 float fr, fg, fb, fa;
899 fr = ((rgba & 0xff000000) >> 24) / 255.0f;
900 fg = ((rgba & 0xff0000) >> 16) / 255.0f;
901 fb = ((rgba & 0xff00) >> 8) / 255.0f;
902 fa = (rgba & 0xff) / 255.0f;
904 cairo_set_source_rgba (cr, fr, fg, fb, fa);
905 cairo_select_font_face (cr, font->get_family().c_str(),
906 CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
907 cairo_set_font_size (cr, font->get_size() / Pango::SCALE);
908 cairo_text_extents (cr, name.c_str(), &te);
910 cairo_move_to (cr, 0.5, 0.5 - te.height / 2 - te.y_bearing + clip_height / 2);
911 cairo_show_text (cr, name.c_str());
913 convert_bgra_to_rgba(cairo_image_surface_get_data (surface), buf->get_pixels(), clip_width, clip_height);
915 cairo_destroy(cr);
916 cairo_surface_destroy(surface);
918 return buf;