*/
+#if !defined USE_CAIRO_IMAGE_SURFACE && !defined NDEBUG
+#define OPTIONAL_CAIRO_IMAGE_SURFACE
+#endif
+
/** @file canvas/canvas.cc
* @brief Implementation of the main canvas classes.
*/
(*i)->scroll_to (Duple (x, y));
}
- pick_current_item (0); // no current mouse position
+ pick_current_item (0); // no current mouse position
}
void
#endif
render_count = 0;
-
+
boost::optional<Rect> root_bbox = _root.bounding_box();
if (!root_bbox) {
/* the root has no bounding box, so there's nothing to render */
boost::optional<Rect> draw = root_bbox->intersection (area);
if (draw) {
-
+
/* there's a common area between the root and the requested
area, so render it.
*/
std::string
Canvas::indent() const
-{
+{
string s;
for (int n = 0; n < ArdourCanvas::dump_depth; ++n) {
std::string
Canvas::render_indent() const
-{
+{
string s;
for (int n = 0; n < ArdourCanvas::render_depth; ++n) {
{
dump_depth = 0;
_root.dump (o);
-}
+}
/** Called when an item has been shown or hidden.
* @param item Item that has been shown or hidden.
void
Canvas::item_changed (Item* item, boost::optional<Rect> pre_change_bounding_box)
{
-
+
Rect window_bbox = visible_area ();
if (pre_change_bounding_box) {
boost::optional<Rect> post_change_bounding_box = item->bounding_box ();
if (post_change_bounding_box) {
-
+
if (item->item_to_window (*post_change_bounding_box).intersection (window_bbox)) {
/* request a redraw of the item's new bounding box */
queue_draw_item_area (item, post_change_bounding_box.get ());
/* XXX January 22nd 2015: leaving this in place for now
* but I think it fixes a bug that really should be
* fixed in a different way (and will be) by my next
- * commit. But it may still be relevant.
+ * commit. But it may still be relevant.
*/
/* If scroll groups overlap, choose the one with the highest sensitivity,
that is, choose an HV scroll group over an H or V
- only group.
+ only group.
*/
if (!best_group || sg->sensitivity() > best_group->sensitivity()) {
best_group = sg;
, _single_exposure (1)
, current_tooltip_item (0)
, tooltip_window (0)
+ , _in_dtor (false)
{
/* these are the events we want to know about */
add_events (Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK |
* added or removed, so we have no coordinates to work from as is the
* case with a motion event. Find out where the mouse is and use that.
*/
-
+
Glib::RefPtr<const Gdk::Window> pointer_window = Gdk::Display::get_default()->get_window_at_pointer (x, y);
if (pointer_window != get_window()) {
top, but we're going to reverse that for within_items so that its
first item is the upper-most item that can be chosen as _current_item.
*/
-
+
vector<Item const *>::const_iterator i;
list<Item const *> within_items;
DEBUG_TRACE (PBD::DEBUG::CanvasEnterLeave, string_compose ("CURRENT ITEM %1/%2\n", _new_current_item->whatami(), _current_item->name));
return;
}
-
+
_new_current_item = const_cast<Item*> (within_items.front());
}
/* Events delivered to canvas items are expected to be in canvas
* coordinates but @param point is in window coordinates.
*/
-
+
Duple c = window_to_canvas (point);
enter_event.x = c.x;
enter_event.y = c.y;
enter_detail = GDK_NOTIFY_UNKNOWN;
/* no current item, so also send virtual enter events to the
- * entire heirarchy for the new item
+ * entire heirarchy for the new item
*/
for (i = _new_current_item->parent(); i ; i = i->parent()) {
} else if (_current_item->is_descendant_of (*_new_current_item)) {
/* move from descendant to ancestor (X: "_current_item is an
- * inferior ("child") of _new_current_item")
+ * inferior ("child") of _new_current_item")
*
* Deliver "virtual" leave notifications to all items in the
* heirarchy between current and new_current.
*/
-
+
for (i = _current_item->parent(); i && i != _new_current_item; i = i->parent()) {
items_to_leave_virtual.push_back (i);
}
enter_detail = GDK_NOTIFY_NONLINEAR;
leave_detail = GDK_NOTIFY_NONLINEAR;
}
-
+
if (_current_item && !_current_item->ignore_events ()) {
leave_event.detail = leave_detail;
/* run through the items from child to parent, until one claims the event */
Item* item = const_cast<Item*> (event_item);
-
+
while (item) {
Item* parent = item->parent ();
- if (!item->ignore_events () &&
+ if (!item->ignore_events () &&
item->Event (event)) {
/* this item has just handled the event */
DEBUG_TRACE (
PBD::DEBUG::CanvasEvents,
string_compose ("canvas event handled by %1 %2\n", item->whatami(), item->name.empty() ? "[unknown]" : item->name)
);
-
+
return true;
}
-
+
DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("canvas event %3 left unhandled by %1 %2\n", item->whatami(), item->name.empty() ? "[unknown]" : item->name, event_type_string (event->type)));
if ((item = parent) == 0) {
if (bounding_box) {
queue_draw_item_area (item, bounding_box.get ());
}
-
+
if (_new_current_item == item) {
_new_current_item = 0;
}
}
if (_current_item == item) {
- /* no need to send a leave event to this item, since it is going away
+ /* no need to send a leave event to this item, since it is going away
*/
_current_item = 0;
pick_current_item (0); // no mouse state
}
-
+
}
void
GtkCanvas::on_size_allocate (Gtk::Allocation& a)
{
EventBox::on_size_allocate (a);
-#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
/* allocate an image surface as large as the canvas itself */
canvas_image.clear ();
canvas_image = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, a.get_width(), a.get_height());
#endif
+#ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
+ }
+#endif
}
/** Handler for GDK expose events.
bool
GtkCanvas::on_expose_event (GdkEventExpose* ev)
{
-#ifdef USE_CAIRO_IMAGE_SURFACE
+ if (_in_dtor) {
+ return true;
+ }
+
+#ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
+ Cairo::RefPtr<Cairo::Context> draw_context;
+ Cairo::RefPtr<Cairo::Context> window_context;
+ if (getenv("ARDOUR_IMAGE_SURFACE")) {
+ if (!canvas_image) {
+ canvas_image = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, get_width(), get_height());
+ }
+ draw_context = Cairo::Context::create (canvas_image);
+ window_context = get_window()->create_cairo_context ();
+ } else {
+ draw_context = get_window()->create_cairo_context ();
+ }
+#elif defined USE_CAIRO_IMAGE_SURFACE
if (!canvas_image) {
canvas_image = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, get_width(), get_height());
}
Cairo::RefPtr<Cairo::Context> draw_context = Cairo::Context::create (canvas_image);
Cairo::RefPtr<Cairo::Context> window_context = get_window()->create_cairo_context ();
-#else
+#else
Cairo::RefPtr<Cairo::Context> draw_context = get_window()->create_cairo_context ();
#endif
/* draw background color */
-
+
draw_context->rectangle (ev->area.x, ev->area.y, ev->area.width, ev->area.height);
draw_context->clip_preserve ();
set_source_rgba (draw_context, _bg_color);
draw_context->fill ();
-
+
/* render canvas */
if ( _single_exposure ) {
-
+
render (Rect (ev->area.x, ev->area.y, ev->area.x + ev->area.width, ev->area.y + ev->area.height), draw_context);
} else {
GdkRectangle* rects;
gint nrects;
-
+
gdk_region_get_rectangles (ev->region, &rects, &nrects);
for (gint n = 0; n < nrects; ++n) {
draw_context->set_identity_matrix(); //reset the cairo matrix, just in case someone left it transformed after drawing ( cough )
}
g_free (rects);
}
-
-#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
/* now blit our private surface back to the GDK one */
window_context->rectangle (ev->area.x, ev->area.y, ev->area.width, ev->area.height);
window_context->set_operator (Cairo::OPERATOR_SOURCE);
window_context->paint ();
#endif
+#ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
+ }
+#endif
return true;
}
GdkEvent copy = *((GdkEvent*)ev);
Duple winpos = Duple (ev->x, ev->y);
Duple where = window_to_canvas (winpos);
-
+
pick_current_item (winpos, ev->state);
copy.button.x = where.x;
copy.button.y = where.y;
-
+
/* Coordinates in the event will be canvas coordinates, correctly adjusted
for scroll if this GtkCanvas is in a GtkCanvasViewport.
*/
GdkEvent copy = *((GdkEvent*)ev);
Duple winpos = Duple (ev->x, ev->y);
Duple where = window_to_canvas (winpos);
-
+
pick_current_item (winpos, ev->state);
copy.button.x = where.x;
copy.button.y = where.y;
-
+
/* Coordinates in the event will be canvas coordinates, correctly adjusted
for scroll if this GtkCanvas is in a GtkCanvasViewport.
*/
- DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("canvas button press @ %1, %2 => %3\n", ev->x, ev->y, where));
+ DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("canvas button press %1 @ %2, %3 => %4\n", ev->button, ev->x, ev->y, where));
return deliver_event (reinterpret_cast<GdkEvent*>(©));
}
*/
bool
GtkCanvas::on_button_release_event (GdkEventButton* ev)
-{
+{
/* translate event coordinates from window to canvas */
GdkEvent copy = *((GdkEvent*)ev);
Duple winpos = Duple (ev->x, ev->y);
Duple where = window_to_canvas (winpos);
-
+
pick_current_item (winpos, ev->state);
copy.button.x = where.x;
for scroll if this GtkCanvas is in a GtkCanvasViewport.
*/
- DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("canvas button release @ %1, %2 => %3\n", ev->x, ev->y, where));
+ DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("canvas button release %1 @ %2, %3 => %4\n", ev->button, ev->x, ev->y, where));
return deliver_event (reinterpret_cast<GdkEvent*>(©));
}
copy.motion.x = where.x;
copy.motion.y = where.y;
- /* Coordinates in "copy" will be canvas coordinates,
+ /* Coordinates in "copy" will be canvas coordinates,
*/
DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("canvas motion @ %1, %2 canvas @ %3, %4\n", ev->x, ev->y, copy.motion.x, copy.motion.y));
void
GtkCanvas::request_redraw (Rect const & request)
{
+ if (_in_dtor) {
+ return;
+ }
+
Rect real_area;
Coord const w = width ();
(void) toplevel->get_window()->get_pointer (pointer_x, pointer_y, mask);
Duple tooltip_window_origin (pointer_x, pointer_y);
-
+
/* convert to root window coordinates */
int win_x, win_y;
dynamic_cast<Gtk::Window*>(toplevel)->get_position (win_x, win_y);
-
+
tooltip_window_origin = tooltip_window_origin.translate (Duple (win_x, win_y));
/* we don't want the pointer to be inside the window when it is
/* ready to show */
tooltip_window->present ();
-
+
/* called from a timeout handler, don't call it again */
return false;
GtkCanvasViewport::on_size_request (Gtk::Requisition* req)
{
/* force the canvas to size itself */
- // _canvas.root()->bounding_box();
+ // _canvas.root()->bounding_box();
req->width = 16;
req->height = 16;