map::clear() calls erase. Cleans up cpp check warning 'iterator used after element...
[ardour.git] / libs / gtkmm2ext / cairo_widget.cc
index 5180c2e8d0f37f592c4f14478983d9aabde22875..8349a685fa4dc50340278298d7bb7c9a7a3197a3 100644 (file)
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
 */
+#if !defined USE_CAIRO_IMAGE_SURFACE && !defined NDEBUG
+#define OPTIONAL_CAIRO_IMAGE_SURFACE
+#endif
 
 #include "gtkmm2ext/cairo_widget.h"
 #include "gtkmm2ext/gui_thread.h"
 
-#include "i18n.h"
+#include "pbd/i18n.h"
 
 static const char* has_cairo_widget_background_info = "has_cairo_widget_background_info";
 
 bool CairoWidget::_flat_buttons = false;
+bool CairoWidget::_widget_prelight = true;
 
-static void noop() { }
-sigc::slot<void> CairoWidget::focus_handler (sigc::ptr_fun (noop));
+sigc::slot<void,Gtk::Widget*> CairoWidget::focus_handler;
 
 void CairoWidget::set_source_rgb_a( cairo_t* cr, Gdk::Color col, float a)  //ToDo:  this one and the Canvas version should be in a shared file (?)
 {
        float r = col.get_red_p ();
        float g = col.get_green_p ();
        float b = col.get_blue_p ();
-       
+
        cairo_set_source_rgba(cr, r, g, b, a);
 }
 
@@ -57,14 +60,117 @@ CairoWidget::~CairoWidget ()
 bool
 CairoWidget::on_button_press_event (GdkEventButton*)
 {
-       focus_handler();
+       focus_handler (this);
        return false;
 }
 
+
+#ifdef USE_TRACKS_CODE_FEATURES
+
+/* This is Tracks version of this method.
+
+   The use of get_visible_window() in this method is an abuse of the GDK/GTK
+   semantics. It can and may break on different GDK backends, and uses a
+   side-effect/unintended behaviour in GDK/GTK to try to accomplish something
+   which should be done differently. I (Paul) have confirmed this with the GTK
+   development team.
+
+   For this reason, this code is not acceptable for ordinary merging into the Ardour libraries.
+
+   Ardour Developers: you are not obligated to maintain the internals of this
+   implementation in the face of build-time environment changes (e.g. -D
+   defines etc).
+*/
+
 bool
 CairoWidget::on_expose_event (GdkEventExpose *ev)
 {
-#ifdef USE_CAIRO_IMAGE_SURFACE
+       cairo_rectangle_t expose_area;
+       expose_area.width = ev->area.width;
+       expose_area.height = ev->area.height;
+
+#ifdef USE_CAIRO_IMAGE_SURFACE_FOR_CAIRO_WIDGET
+       Cairo::RefPtr<Cairo::Context> cr;
+       if (get_visible_window ()) {
+               expose_area.x = 0;
+               expose_area.y = 0;
+               if (!_image_surface) {
+                       _image_surface = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, get_width(), get_height());
+               }
+               cr = Cairo::Context::create (_image_surface);
+       } else {
+               expose_area.x = ev->area.x;
+               expose_area.y = ev->area.y;
+               cr = get_window()->create_cairo_context ();
+       }
+#else
+       expose_area.x = ev->area.x;
+       expose_area.y = ev->area.y;
+       Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context ();
+#endif
+
+       cr->rectangle (expose_area.x, expose_area.y, expose_area.width, expose_area.height);
+       cr->clip ();
+
+       /* paint expose area the color of the parent window bg
+       */
+
+    if (get_visible_window ()) {
+        Gdk::Color bg (get_parent_bg());
+               cr->rectangle (expose_area.x, expose_area.y, expose_area.width, expose_area.height);
+        cr->set_source_rgb (bg.get_red_p(), bg.get_green_p(), bg.get_blue_p());
+        cr->fill ();
+    }
+
+       render (cr->cobj(), &expose_area);
+
+#ifdef USE_CAIRO_IMAGE_SURFACE_FOR_CAIRO_WIDGET
+       if(get_visible_window ()) {
+               _image_surface->flush();
+               /* now blit our private surface back to the GDK one */
+
+               Cairo::RefPtr<Cairo::Context> cairo_context = get_window()->create_cairo_context ();
+
+               cairo_context->rectangle (ev->area.x, ev->area.y, ev->area.width, ev->area.height);
+               cairo_context->clip ();
+               cairo_context->set_source (_image_surface, ev->area.x, ev->area.y);
+               cairo_context->set_operator (Cairo::OPERATOR_OVER);
+               cairo_context->paint ();
+       }
+#endif
+
+       Gtk::Widget* child = get_child ();
+
+       if (child) {
+               propagate_expose (*child, ev);
+       }
+
+       return true;
+}
+
+#else
+
+/* Ardour mainline: not using Tracks code features.
+
+   Tracks Developers: please do not modify this version of
+   ::on_expose_event(). The version used by Tracks is before the preceding
+   #else and contains hacks required for the Tracks GUI to work.
+*/
+
+bool
+CairoWidget::on_expose_event (GdkEventExpose *ev)
+{
+#ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
+       Cairo::RefPtr<Cairo::Context> cr;
+       if (getenv("ARDOUR_IMAGE_SURFACE")) {
+               if (!image_surface) {
+                       image_surface = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, get_width(), get_height());
+               }
+               cr = Cairo::Context::create (image_surface);
+       } else {
+               cr = get_window()->create_cairo_context ();
+       }
+#elif defined USE_CAIRO_IMAGE_SURFACE
 
        if (!image_surface) {
                image_surface = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, get_width(), get_height());
@@ -76,15 +182,21 @@ CairoWidget::on_expose_event (GdkEventExpose *ev)
 #endif
 
        cr->rectangle (ev->area.x, ev->area.y, ev->area.width, ev->area.height);
-       cr->clip_preserve ();
 
-       /* paint expose area the color of the parent window bg
-       */
-       
-       Gdk::Color bg (get_parent_bg());
-       
-       cr->set_source_rgb (bg.get_red_p(), bg.get_green_p(), bg.get_blue_p());
-       cr->fill ();
+       if (_need_bg) {
+               cr->clip_preserve ();
+
+               /* paint expose area the color of the parent window bg
+                */
+
+               Gdk::Color bg (get_parent_bg());
+
+               cr->set_source_rgb (bg.get_red_p(), bg.get_green_p(), bg.get_blue_p());
+               cr->fill ();
+       } else {
+               std::cerr << get_name() << " skipped bg fill\n";
+               cr->clip ();
+       }
 
        cairo_rectangle_t expose_area;
        expose_area.x = ev->area.x;
@@ -94,7 +206,10 @@ CairoWidget::on_expose_event (GdkEventExpose *ev)
 
        render (cr->cobj(), &expose_area);
 
-#ifdef USE_CAIRO_IMAGE_SURFACE
+#ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
+       if (getenv("ARDOUR_IMAGE_SURFACE")) {
+#endif
+#if defined USE_CAIRO_IMAGE_SURFACE || defined OPTIONAL_CAIRO_IMAGE_SURFACE
        image_surface->flush();
        /* now blit our private surface back to the GDK one */
 
@@ -106,19 +221,28 @@ CairoWidget::on_expose_event (GdkEventExpose *ev)
        cairo_context->set_operator (Cairo::OPERATOR_SOURCE);
        cairo_context->paint ();
 #endif
+#ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
+       }
+#endif
 
        return true;
 }
 
+#endif
+
 /** Marks the widget as dirty, so that render () will be called on
  *  the next GTK expose event.
  */
 
 void
-CairoWidget::set_dirty ()
+CairoWidget::set_dirty (cairo_rectangle_t *area)
 {
        ENSURE_GUI_THREAD (*this, &CairoWidget::set_dirty);
-       queue_draw ();
+       if (!area) {
+               queue_draw ();
+       } else {
+               queue_draw_area (area->x, area->y, area->width, area->height);
+       }
 }
 
 /** Handle a size allocation.
@@ -129,9 +253,15 @@ CairoWidget::on_size_allocate (Gtk::Allocation& alloc)
 {
        Gtk::EventBox::on_size_allocate (alloc);
 
-#ifdef USE_CAIRO_IMAGE_SURFACE
+#ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
+       if (getenv("ARDOUR_IMAGE_SURFACE")) {
+#endif
+#if defined USE_CAIRO_IMAGE_SURFACE || defined OPTIONAL_CAIRO_IMAGE_SURFACE
        image_surface = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, alloc.get_width(), alloc.get_height());
 #endif
+#ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
+       }
+#endif
 
        set_dirty ();
 }
@@ -257,7 +387,13 @@ CairoWidget::set_flat_buttons (bool yn)
 }
 
 void
-CairoWidget::set_focus_handler (sigc::slot<void> s)
+CairoWidget::set_widget_prelight (bool yn)
+{
+       _widget_prelight = yn;
+}
+
+void
+CairoWidget::set_focus_handler (sigc::slot<void,Gtk::Widget*> s)
 {
        focus_handler = s;
 }