+ if (current_level == old_level && current_peak == old_peak && hold_state == 0) {
+ return;
+ }
+
+
+ Glib::RefPtr<Gdk::Window> win;
+
+ if ((win = get_window()) == 0) {
+ queue_draw ();
+ return;
+ }
+
+ if (orientation == Vertical) {
+ queue_vertical_redraw (win, old_level);
+ } else {
+ queue_horizontal_redraw (win, old_level);
+ }
+}
+
+void
+FastMeter::queue_vertical_redraw (const Glib::RefPtr<Gdk::Window>& win, float old_level)
+{
+ GdkRectangle rect;
+
+ gint new_top = (gint) floor (pixheight * current_level);
+
+ rect.x = 0;
+ rect.width = pixwidth;
+ rect.height = new_top;
+ rect.y = pixheight - new_top;
+
+ if (current_level > old_level) {
+ /* colored/pixbuf got larger, just draw the new section */
+ /* rect.y stays where it is because of X coordinates */
+ /* height of invalidated area is between new.y (smaller) and old.y
+ (larger).
+ X coordinates just make my brain hurt.
+ */
+ rect.height = pixrect.y - rect.y;
+ } else {
+ /* it got smaller, compute the difference */
+ /* rect.y becomes old.y (the smaller value) */
+ rect.y = pixrect.y;
+ /* rect.height is the old.y (smaller) minus the new.y (larger)
+ */
+ rect.height = pixrect.height - rect.height;
+ }
+
+ GdkRegion* region = 0;
+ bool queue = false;
+
+ if (rect.height != 0) {
+
+ /* ok, first region to draw ... */
+
+ region = gdk_region_rectangle (&rect);
+ queue = true;
+ }
+
+ /* redraw the last place where the last peak hold bar was;
+ the next expose will draw the new one whether its part of
+ expose region or not.
+ */
+
+ if (last_peak_rect.width * last_peak_rect.height != 0) {
+ if (!queue) {
+ region = gdk_region_new ();
+ queue = true;
+ }
+ gdk_region_union_with_rect (region, &last_peak_rect);
+ }
+
+ if (queue) {
+ gdk_window_invalidate_region (win->gobj(), region, true);
+ }
+ if (region) {
+ gdk_region_destroy(region);
+ region = 0;
+ }
+}
+
+void
+FastMeter::queue_horizontal_redraw (const Glib::RefPtr<Gdk::Window>& /*win*/, float /*old_level*/)
+{
+ /* XXX OPTIMIZE (when we have some horizontal meters) */