2 Copyright (C) 2003-2006 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.
28 #include <gdkmm/rectangle.h>
29 #include <gtkmm2ext/fastmeter.h>
30 #include <gtkmm2ext/utils.h>
32 #define UINT_TO_RGB(u,r,g,b) { (*(r)) = ((u)>>16)&0xff; (*(g)) = ((u)>>8)&0xff; (*(b)) = (u)&0xff; }
33 #define UINT_TO_RGBA(u,r,g,b,a) { UINT_TO_RGB(((u)>>8),r,g,b); (*(a)) = (u)&0xff; }
37 using namespace Gtkmm2ext;
40 int FastMeter::min_pattern_metric_size = 16;
41 int FastMeter::max_pattern_metric_size = 1024;
42 bool FastMeter::no_rgba_overlay = false;
44 FastMeter::Pattern10Map FastMeter::vm_pattern_cache;
45 FastMeter::PatternBgMap FastMeter::vb_pattern_cache;
47 FastMeter::Pattern10Map FastMeter::hm_pattern_cache;
48 FastMeter::PatternBgMap FastMeter::hb_pattern_cache;
50 FastMeter::FastMeter (long hold, unsigned long dimen, Orientation o, int len,
51 int clr0, int clr1, int clr2, int clr3,
52 int clr4, int clr5, int clr6, int clr7,
56 float stp0, float stp1,
57 float stp2, float stp3,
62 , _styleflags(styleflags)
71 last_peak_rect.width = 0;
72 last_peak_rect.height = 0;
76 no_rgba_overlay = ! Glib::getenv("NO_METER_SHADE").empty();
100 set_events (BUTTON_PRESS_MASK|BUTTON_RELEASE_MASK);
108 if (orientation == Vertical) {
111 fgpattern = request_vertical_meter(pixwidth + 2, pixheight + 2, _clr, _stp, _styleflags);
112 bgpattern = request_vertical_background (pixwidth + 2, pixheight + 2, _bgc, false);
117 fgpattern = request_horizontal_meter(pixwidth + 2, pixheight + 2, _clr, _stp, _styleflags);
118 bgpattern = request_horizontal_background (pixwidth + 2, pixheight + 2, _bgc, false);
121 pixrect.width = pixwidth;
122 pixrect.height = pixheight;
124 request_width = pixrect.width + 2;
125 request_height= pixrect.height + 2;
130 FastMeter::~FastMeter ()
134 Cairo::RefPtr<Cairo::Pattern>
135 FastMeter::generate_meter_pattern (
136 int width, int height, int *clr, float *stp, int styleflags, bool horiz)
140 const double soft = 3.0 / (double) height;
141 const double offs = -1.0 / (double) height;
143 cairo_pattern_t* pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, height);
146 Cairo coordinate space goes downwards as y value goes up, so invert
147 knee-based positions by using (1.0 - y)
150 UINT_TO_RGBA (clr[9], &r, &g, &b, &a); // top/clip
151 cairo_pattern_add_color_stop_rgb (pat, 0.0,
152 r/255.0, g/255.0, b/255.0);
154 knee = offs + stp[3] / 115.0f; // -0dB
156 UINT_TO_RGBA (clr[8], &r, &g, &b, &a);
157 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
158 r/255.0, g/255.0, b/255.0);
160 UINT_TO_RGBA (clr[7], &r, &g, &b, &a);
161 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
162 r/255.0, g/255.0, b/255.0);
164 knee = offs + stp[2]/ 115.0f; // -3dB || -2dB
166 UINT_TO_RGBA (clr[6], &r, &g, &b, &a);
167 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
168 r/255.0, g/255.0, b/255.0);
170 UINT_TO_RGBA (clr[5], &r, &g, &b, &a);
171 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
172 r/255.0, g/255.0, b/255.0);
174 knee = offs + stp[1] / 115.0f; // -9dB
176 UINT_TO_RGBA (clr[4], &r, &g, &b, &a);
177 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
178 r/255.0, g/255.0, b/255.0);
180 UINT_TO_RGBA (clr[3], &r, &g, &b, &a);
181 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
182 r/255.0, g/255.0, b/255.0);
184 knee = offs + stp[0] / 115.0f; // -18dB
186 UINT_TO_RGBA (clr[2], &r, &g, &b, &a);
187 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
188 r/255.0, g/255.0, b/255.0);
190 UINT_TO_RGBA (clr[1], &r, &g, &b, &a);
191 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
192 r/255.0, g/255.0, b/255.0);
194 UINT_TO_RGBA (clr[0], &r, &g, &b, &a); // bottom
195 cairo_pattern_add_color_stop_rgb (pat, 1.0,
196 r/255.0, g/255.0, b/255.0);
198 if ((styleflags & 1) && !no_rgba_overlay) {
199 cairo_pattern_t* shade_pattern = cairo_pattern_create_linear (0.0, 0.0, width, 0.0);
200 cairo_pattern_add_color_stop_rgba (shade_pattern, 0, 0.0, 0.0, 0.0, 0.15);
201 cairo_pattern_add_color_stop_rgba (shade_pattern, 0.4, 1.0, 1.0, 1.0, 0.05);
202 cairo_pattern_add_color_stop_rgba (shade_pattern, 1, 0.0, 0.0, 0.0, 0.25);
204 cairo_surface_t* surface;
206 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
207 tc = cairo_create (surface);
208 cairo_set_source (tc, pat);
209 cairo_rectangle (tc, 0, 0, width, height);
211 cairo_pattern_destroy (pat);
213 cairo_set_source (tc, shade_pattern);
214 cairo_rectangle (tc, 0, 0, width, height);
216 cairo_pattern_destroy (shade_pattern);
218 if (styleflags & 2) { // LED stripes
220 cairo_set_line_width(tc, 1.0);
221 cairo_set_source_rgba(tc, .0, .0, .0, 0.4);
222 //cairo_set_operator (tc, CAIRO_OPERATOR_SOURCE);
223 for (float y=0.5; y < height; y+= 2.0) {
224 cairo_move_to(tc, 0, y);
225 cairo_line_to(tc, width, y);
231 pat = cairo_pattern_create_for_surface (surface);
233 cairo_surface_destroy (surface);
237 cairo_surface_t* surface;
239 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, height, width);
240 tc = cairo_create (surface);
243 cairo_matrix_init_rotate (&m, -M_PI/2.0);
244 cairo_matrix_translate (&m, -height, 0);
245 cairo_pattern_set_matrix (pat, &m);
246 cairo_set_source (tc, pat);
247 cairo_rectangle (tc, 0, 0, height, width);
249 cairo_pattern_destroy (pat);
250 pat = cairo_pattern_create_for_surface (surface);
252 cairo_surface_destroy (surface);
254 Cairo::RefPtr<Cairo::Pattern> p (new Cairo::Pattern (pat, false));
260 Cairo::RefPtr<Cairo::Pattern>
261 FastMeter::generate_meter_background (
262 int width, int height, int *clr, bool shade, bool horiz)
264 guint8 r0,g0,b0,r1,g1,b1,a;
266 cairo_pattern_t* pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, height);
268 UINT_TO_RGBA (clr[0], &r0, &g0, &b0, &a);
269 UINT_TO_RGBA (clr[1], &r1, &g1, &b1, &a);
271 cairo_pattern_add_color_stop_rgb (pat, 0.0,
272 r1/255.0, g1/255.0, b1/255.0);
274 cairo_pattern_add_color_stop_rgb (pat, 1.0,
275 r0/255.0, g0/255.0, b0/255.0);
277 if (shade && !no_rgba_overlay) {
278 cairo_pattern_t* shade_pattern = cairo_pattern_create_linear (0.0, 0.0, width, 0.0);
279 cairo_pattern_add_color_stop_rgba (shade_pattern, 0.0, 1.0, 1.0, 1.0, 0.15);
280 cairo_pattern_add_color_stop_rgba (shade_pattern, 0.6, 0.0, 0.0, 0.0, 0.10);
281 cairo_pattern_add_color_stop_rgba (shade_pattern, 1.0, 1.0, 1.0, 1.0, 0.20);
283 cairo_surface_t* surface;
285 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
286 tc = cairo_create (surface);
287 cairo_set_source (tc, pat);
288 cairo_rectangle (tc, 0, 0, width, height);
290 cairo_set_source (tc, shade_pattern);
291 cairo_rectangle (tc, 0, 0, width, height);
294 cairo_pattern_destroy (pat);
295 cairo_pattern_destroy (shade_pattern);
297 pat = cairo_pattern_create_for_surface (surface);
300 cairo_surface_destroy (surface);
304 cairo_surface_t* surface;
306 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, height, width);
307 tc = cairo_create (surface);
310 cairo_matrix_init_rotate (&m, -M_PI/2.0);
311 cairo_matrix_translate (&m, -height, 0);
312 cairo_pattern_set_matrix (pat, &m);
313 cairo_set_source (tc, pat);
314 cairo_rectangle (tc, 0, 0, height, width);
316 cairo_pattern_destroy (pat);
317 pat = cairo_pattern_create_for_surface (surface);
319 cairo_surface_destroy (surface);
322 Cairo::RefPtr<Cairo::Pattern> p (new Cairo::Pattern (pat, false));
327 Cairo::RefPtr<Cairo::Pattern>
328 FastMeter::request_vertical_meter(
329 int width, int height, int *clr, float *stp, int styleflags)
331 height = max(height, min_pattern_metric_size);
332 height = min(height, max_pattern_metric_size);
334 const Pattern10MapKey key (width, height,
335 stp[0], stp[1], stp[2], stp[3],
336 clr[0], clr[1], clr[2], clr[3],
337 clr[4], clr[5], clr[6], clr[7],
338 clr[8], clr[9], styleflags);
340 Pattern10Map::iterator i;
341 if ((i = vm_pattern_cache.find (key)) != vm_pattern_cache.end()) {
344 // TODO flush pattern cache if it gets too large
346 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_pattern (
347 width, height, clr, stp, styleflags, false);
348 vm_pattern_cache[key] = p;
353 Cairo::RefPtr<Cairo::Pattern>
354 FastMeter::request_vertical_background(
355 int width, int height, int *bgc, bool shade)
357 height = max(height, min_pattern_metric_size);
358 height = min(height, max_pattern_metric_size);
361 const PatternBgMapKey key (width, height, bgc[0], bgc[1], shade);
362 PatternBgMap::iterator i;
363 if ((i = vb_pattern_cache.find (key)) != vb_pattern_cache.end()) {
366 // TODO flush pattern cache if it gets too large
368 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_background (
369 width, height, bgc, shade, false);
370 vb_pattern_cache[key] = p;
375 Cairo::RefPtr<Cairo::Pattern>
376 FastMeter::request_horizontal_meter(
377 int width, int height, int *clr, float *stp, int styleflags)
379 width = max(width, min_pattern_metric_size);
380 width = min(width, max_pattern_metric_size);
382 const Pattern10MapKey key (width, height,
383 stp[0], stp[1], stp[2], stp[3],
384 clr[0], clr[1], clr[2], clr[3],
385 clr[4], clr[5], clr[6], clr[7],
386 clr[8], clr[9], styleflags);
388 Pattern10Map::iterator i;
389 if ((i = hm_pattern_cache.find (key)) != hm_pattern_cache.end()) {
392 // TODO flush pattern cache if it gets too large
394 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_pattern (
395 height, width, clr, stp, styleflags, true);
397 hm_pattern_cache[key] = p;
401 Cairo::RefPtr<Cairo::Pattern>
402 FastMeter::request_horizontal_background(
403 int width, int height, int *bgc, bool shade)
405 width = max(width, min_pattern_metric_size);
406 width = min(width, max_pattern_metric_size);
409 const PatternBgMapKey key (width, height, bgc[0], bgc[1], shade);
410 PatternBgMap::iterator i;
411 if ((i = hb_pattern_cache.find (key)) != hb_pattern_cache.end()) {
414 // TODO flush pattern cache if it gets too large
416 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_background (
417 height, width, bgc, shade, true);
419 hb_pattern_cache[key] = p;
427 FastMeter::set_hold_count (long val)
441 FastMeter::on_size_request (GtkRequisition* req)
443 if (orientation == Vertical) {
444 vertical_size_request (req);
446 horizontal_size_request (req);
451 FastMeter::vertical_size_request (GtkRequisition* req)
453 req->height = request_height;
454 req->height = max(req->height, min_pattern_metric_size);
455 req->height = min(req->height, max_pattern_metric_size);
458 req->width = request_width;
462 FastMeter::horizontal_size_request (GtkRequisition* req)
464 req->width = request_width;
465 req->width = max(req->width, min_pattern_metric_size);
466 req->width = min(req->width, max_pattern_metric_size);
469 req->height = request_height;
473 FastMeter::on_size_allocate (Gtk::Allocation &alloc)
475 if (orientation == Vertical) {
476 vertical_size_allocate (alloc);
478 horizontal_size_allocate (alloc);
484 FastMeter::vertical_size_allocate (Gtk::Allocation &alloc)
486 if (alloc.get_width() != request_width) {
487 alloc.set_width (request_width);
490 int h = alloc.get_height();
491 h = max (h, min_pattern_metric_size + 2);
492 h = min (h, max_pattern_metric_size + 2);
494 if (h != alloc.get_height()) {
495 alloc.set_height (h);
498 if (pixheight != h) {
499 fgpattern = request_vertical_meter (request_width, h, _clr, _stp, _styleflags);
500 bgpattern = request_vertical_background (request_width, h, highlight ? _bgh : _bgc, highlight);
502 pixwidth = request_width - 2;
505 DrawingArea::on_size_allocate (alloc);
509 FastMeter::horizontal_size_allocate (Gtk::Allocation &alloc)
511 if (alloc.get_height() != request_height) {
512 alloc.set_height (request_height);
515 int w = alloc.get_width();
516 w = max (w, min_pattern_metric_size + 2);
517 w = min (w, max_pattern_metric_size + 2);
519 if (w != alloc.get_width()) {
524 fgpattern = request_horizontal_meter (w, request_height, _clr, _stp, _styleflags);
525 bgpattern = request_horizontal_background (w, request_height, highlight ? _bgh : _bgc, highlight);
527 pixheight = request_height - 2;
530 DrawingArea::on_size_allocate (alloc);
534 FastMeter::on_expose_event (GdkEventExpose* ev)
536 if (orientation == Vertical) {
537 return vertical_expose (ev);
539 return horizontal_expose (ev);
544 FastMeter::vertical_expose (GdkEventExpose* ev)
546 Glib::RefPtr<Gdk::Window> win = get_window ();
548 GdkRectangle intersection;
549 GdkRectangle background;
551 cairo_t* cr = gdk_cairo_create (get_window ()->gobj());
553 cairo_rectangle (cr, ev->area.x, ev->area.y, ev->area.width, ev->area.height);
556 cairo_set_source_rgb (cr, 0, 0, 0); // black
557 rounded_rectangle (cr, 0, 0, pixwidth + 2, pixheight + 2, 2);
560 top_of_meter = (gint) floor (pixheight * current_level);
562 /* reset the height & origin of the rect that needs to show the pixbuf
565 pixrect.height = top_of_meter;
566 pixrect.y = 1 + pixheight - top_of_meter;
570 background.width = pixrect.width;
571 background.height = pixheight - top_of_meter;
573 if (gdk_rectangle_intersect (&background, &ev->area, &intersection)) {
574 cairo_set_source (cr, bgpattern->cobj());
575 cairo_rectangle (cr, intersection.x, intersection.y, intersection.width, intersection.height);
579 if (gdk_rectangle_intersect (&pixrect, &ev->area, &intersection)) {
580 // draw the part of the meter image that we need. the area we draw is bounded "in reverse" (top->bottom)
581 cairo_set_source (cr, fgpattern->cobj());
582 cairo_rectangle (cr, intersection.x, intersection.y, intersection.width, intersection.height);
589 last_peak_rect.x = 1;
590 last_peak_rect.width = pixwidth;
591 last_peak_rect.y = max(1, 1 + pixheight - (gint) floor (pixheight * current_peak));
592 if (bright_hold || (_styleflags & 2)) {
593 last_peak_rect.height = max(0, min(3, pixheight - last_peak_rect.y - 1 ));
595 last_peak_rect.height = max(0, min(2, pixheight - last_peak_rect.y - 1 ));
598 cairo_set_source (cr, fgpattern->cobj());
599 cairo_rectangle (cr, last_peak_rect.x, last_peak_rect.y, last_peak_rect.width, last_peak_rect.height);
601 if (bright_hold && !no_rgba_overlay) {
602 cairo_fill_preserve (cr);
603 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.3);
608 last_peak_rect.width = 0;
609 last_peak_rect.height = 0;
618 FastMeter::horizontal_expose (GdkEventExpose* ev)
620 Glib::RefPtr<Gdk::Window> win = get_window ();
622 GdkRectangle intersection;
623 GdkRectangle background;
625 cairo_t* cr = gdk_cairo_create (get_window ()->gobj());
627 cairo_rectangle (cr, ev->area.x, ev->area.y, ev->area.width, ev->area.height);
630 cairo_set_source_rgb (cr, 0, 0, 0); // black
631 rounded_rectangle (cr, 0, 0, pixwidth + 2, pixheight + 2, 2);
634 right_of_meter = (gint) floor (pixwidth * current_level);
636 /* reset the height & origin of the rect that needs to show the pixbuf
639 pixrect.width = right_of_meter;
641 background.x = 1 + right_of_meter;
643 background.width = pixwidth - right_of_meter;
644 background.height = pixheight;
646 if (gdk_rectangle_intersect (&background, &ev->area, &intersection)) {
647 cairo_set_source (cr, bgpattern->cobj());
648 cairo_rectangle (cr, intersection.x, intersection.y, intersection.width, intersection.height);
652 if (gdk_rectangle_intersect (&pixrect, &ev->area, &intersection)) {
653 cairo_set_source (cr, fgpattern->cobj());
654 cairo_rectangle (cr, intersection.x, intersection.y, intersection.width, intersection.height);
661 last_peak_rect.y = 1;
662 last_peak_rect.height = pixheight;
663 const int xpos = floor (pixwidth * current_peak);
664 if (bright_hold || (_styleflags & 2)) {
665 last_peak_rect.width = min(3, xpos );
667 last_peak_rect.width = min(2, xpos );
669 last_peak_rect.x = 1 + max(0, xpos - last_peak_rect.width);
671 cairo_set_source (cr, fgpattern->cobj());
672 cairo_rectangle (cr, last_peak_rect.x, last_peak_rect.y, last_peak_rect.width, last_peak_rect.height);
674 if (bright_hold && !no_rgba_overlay) {
675 cairo_fill_preserve (cr);
676 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.3);
681 last_peak_rect.width = 0;
682 last_peak_rect.height = 0;
691 FastMeter::set (float lvl, float peak)
693 float old_level = current_level;
694 float old_peak = current_peak;
696 if (pixwidth <= 0 || pixheight <=0) return;
699 if (lvl >= current_peak) {
701 hold_state = hold_cnt;
704 if (hold_state > 0) {
705 if (--hold_state == 0) {
718 if (current_level == old_level && current_peak == old_peak && (hold_state == 0 || peak != -1)) {
722 Glib::RefPtr<Gdk::Window> win;
724 if ((win = get_window()) == 0) {
729 if (orientation == Vertical) {
730 queue_vertical_redraw (win, old_level);
732 queue_horizontal_redraw (win, old_level);
737 FastMeter::queue_vertical_redraw (const Glib::RefPtr<Gdk::Window>& win, float old_level)
741 gint new_top = (gint) floor (pixheight * current_level);
744 rect.width = pixwidth;
745 rect.height = new_top;
746 rect.y = 1 + pixheight - new_top;
748 if (current_level > old_level) {
749 /* colored/pixbuf got larger, just draw the new section */
750 /* rect.y stays where it is because of X coordinates */
751 /* height of invalidated area is between new.y (smaller) and old.y
753 X coordinates just make my brain hurt.
755 rect.height = pixrect.y - rect.y;
757 /* it got smaller, compute the difference */
758 /* rect.y becomes old.y (the smaller value) */
760 /* rect.height is the old.y (smaller) minus the new.y (larger)
762 rect.height = pixrect.height - rect.height;
765 GdkRegion* region = 0;
768 if (rect.height != 0) {
770 /* ok, first region to draw ... */
772 region = gdk_region_rectangle (&rect);
776 /* redraw the last place where the last peak hold bar was;
777 the next expose will draw the new one whether its part of
778 expose region or not.
781 if (last_peak_rect.width * last_peak_rect.height != 0) {
783 region = gdk_region_new ();
786 gdk_region_union_with_rect (region, &last_peak_rect);
789 if (hold_state && current_peak > 0) {
791 region = gdk_region_new ();
795 rect.y = max(1, 1 + pixheight - (gint) floor (pixheight * current_peak));
796 if (bright_hold || (_styleflags & 2)) {
797 rect.height = max(0, min(3, pixheight - last_peak_rect.y -1 ));
799 rect.height = max(0, min(2, pixheight - last_peak_rect.y -1 ));
801 rect.width = pixwidth;
802 gdk_region_union_with_rect (region, &rect);
806 gdk_window_invalidate_region (win->gobj(), region, true);
809 gdk_region_destroy(region);
815 FastMeter::queue_horizontal_redraw (const Glib::RefPtr<Gdk::Window>& win, float old_level)
819 gint new_right = (gint) floor (pixwidth * current_level);
821 rect.height = pixheight;
824 if (current_level > old_level) {
825 rect.x = 1 + pixrect.width;
826 /* colored/pixbuf got larger, just draw the new section */
827 rect.width = new_right - pixrect.width;
829 /* it got smaller, compute the difference */
830 rect.x = 1 + new_right;
831 /* rect.height is the old.x (smaller) minus the new.x (larger) */
832 rect.width = pixrect.width - new_right;
835 GdkRegion* region = 0;
838 if (rect.height != 0) {
840 /* ok, first region to draw ... */
842 region = gdk_region_rectangle (&rect);
846 /* redraw the last place where the last peak hold bar was;
847 the next expose will draw the new one whether its part of
848 expose region or not.
851 if (last_peak_rect.width * last_peak_rect.height != 0) {
853 region = gdk_region_new ();
856 gdk_region_union_with_rect (region, &last_peak_rect);
859 if (hold_state && current_peak > 0) {
861 region = gdk_region_new ();
865 rect.height = pixheight;
866 const int xpos = floor (pixwidth * current_peak);
867 if (bright_hold || (_styleflags & 2)) {
868 rect.width = min(3, xpos);
870 rect.width = min(2, xpos);
872 rect.x = 1 + max(0, xpos - rect.width);
873 gdk_region_union_with_rect (region, &rect);
877 gdk_window_invalidate_region (win->gobj(), region, true);
880 gdk_region_destroy(region);
886 FastMeter::set_highlight (bool onoff)
888 if (highlight == onoff) {
892 if (orientation == Vertical) {
893 bgpattern = request_vertical_background (pixwidth + 2, pixheight + 2, highlight ? _bgh : _bgc, highlight);
895 bgpattern = request_horizontal_background (pixwidth + 2, pixheight + 2, highlight ? _bgh : _bgc, highlight);