+ DEBUG_TRACE (PBD::DEBUG::CanvasEnterLeave, string_compose ("%1 covers %2 items\n", point, items.size()));
+
+#ifndef NDEBUG
+ if (DEBUG_ENABLED(PBD::DEBUG::CanvasEnterLeave)) {
+ for (vector<Item const*>::const_iterator it = items.begin(); it != items.end(); ++it) {
+#ifdef CANVAS_DEBUG
+ std::cerr << "\tItem " << (*it)->whatami() << '/' << (*it)->name << std::endl;
+#else
+ std::cerr << "\tItem " << (*it)->whatami() << std::endl;
+#endif
+ }
+ }
+#endif
+
+ /* put all items at point that are event-sensitive and visible and NOT
+ groups into within_items. Note that items is sorted from bottom to
+ 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;
+
+ for (i = items.begin(); i != items.end(); ++i) {
+
+ Item const * possible_item = *i;
+
+ /* We ignore invisible items, containers and items that ignore events */
+
+ if (!possible_item->visible() || possible_item->ignore_events() || dynamic_cast<ArdourCanvas::Container const *>(possible_item) != 0) {
+ continue;
+ }
+ within_items.push_front (possible_item);
+ }
+
+ if (within_items.empty()) {
+
+ /* no items at point, just send leave event below */
+ _new_current_item = 0;
+
+ } else {
+
+ if (within_items.front() == _current_item) {
+ /* uppermost item at point is already _current_item */
+ return;
+ }
+
+ _new_current_item = const_cast<Item*> (within_items.front());
+ }
+
+ if (_new_current_item != _current_item) {
+ deliver_enter_leave (point, state);
+ }
+}
+
+/** Deliver a series of enter & leave events based on the pointer position being at window
+ * coordinate @param point, and pointer @param state (modifier keys, etc)
+ */
+void
+GtkCanvas::deliver_enter_leave (Duple const & point, int state)
+{
+ /* setup enter & leave event structures */
+