fix crash when copy'ing latent plugins
[ardour.git] / libs / canvas / canvas.cc
1 /*
2     Copyright (C) 2011 Paul Davis
3     Author: Carl Hetherington <cth@carlh.net>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20
21 #if !defined USE_CAIRO_IMAGE_SURFACE && !defined NDEBUG
22 #define OPTIONAL_CAIRO_IMAGE_SURFACE
23 #endif
24
25 /** @file  canvas/canvas.cc
26  *  @brief Implementation of the main canvas classes.
27  */
28
29 #include <list>
30 #include <cassert>
31 #include <gtkmm/adjustment.h>
32 #include <gtkmm/label.h>
33 #include <gtkmm/window.h>
34
35 #include "gtkmm2ext/persistent_tooltip.h"
36
37 #include "pbd/compose.h"
38 #include "pbd/stacktrace.h"
39
40 #include "canvas/canvas.h"
41 #include "canvas/colors.h"
42 #include "canvas/debug.h"
43 #include "canvas/line.h"
44 #include "canvas/scroll_group.h"
45 #include "canvas/utils.h"
46
47 using namespace std;
48 using namespace ArdourCanvas;
49
50 uint32_t Canvas::tooltip_timeout_msecs = 750;
51
52 /** Construct a new Canvas */
53 Canvas::Canvas ()
54         : _root (this)
55         , _bg_color (rgba_to_color (0, 1.0, 0.0, 1.0))
56 {
57         set_epoch ();
58 }
59
60 void
61 Canvas::scroll_to (Coord x, Coord y)
62 {
63         /* We do things this way because we do not want to recurse through
64            the canvas for every scroll. In the presence of large MIDI
65            tracks this means traversing item lists that include
66            thousands of items (notes).
67
68            This design limits us to moving only those items (groups, typically)
69            that should move in certain ways as we scroll. In other terms, it
70            becomes O(1) rather than O(N).
71         */
72
73         for (list<ScrollGroup*>::iterator i = scrollers.begin(); i != scrollers.end(); ++i) {
74                 (*i)->scroll_to (Duple (x, y));
75         }
76
77         pick_current_item (0); // no current mouse position
78 }
79
80 void
81 Canvas::add_scroller (ScrollGroup& i)
82 {
83         scrollers.push_back (&i);
84 }
85
86 void
87 Canvas::zoomed ()
88 {
89         pick_current_item (0); // no current mouse position
90 }
91
92 /** Render an area of the canvas.
93  *  @param area Area in window coordinates.
94  *  @param context Cairo context to render to.
95  */
96 void
97 Canvas::render (Rect const & area, Cairo::RefPtr<Cairo::Context> const & context) const
98 {
99 #ifdef CANVAS_DEBUG
100         if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
101                 cerr << this << " RENDER: " << area << endl;
102                 //cerr << "CANVAS @ " << this << endl;
103                 //dump (cerr);
104                 //cerr << "-------------------------\n";
105         }
106 #endif
107
108         render_count = 0;
109
110         boost::optional<Rect> root_bbox = _root.bounding_box();
111         if (!root_bbox) {
112                 /* the root has no bounding box, so there's nothing to render */
113                 return;
114         }
115
116         boost::optional<Rect> draw = root_bbox->intersection (area);
117         if (draw) {
118
119                 /* there's a common area between the root and the requested
120                    area, so render it.
121                 */
122
123                 _root.render (*draw, context);
124
125 #if defined CANVAS_DEBUG && !PLATFORM_WINDOWS
126                 if (getenv ("CANVAS_HARLEQUIN_DEBUGGING")) {
127                         // This transparently colors the rect being rendered, after it has been drawn.
128                         double r = (random() % 65536) /65536.0;
129                         double g = (random() % 65536) /65536.0;
130                         double b = (random() % 65536) /65536.0;
131                         context->rectangle (draw->x0, draw->y0, draw->x1 - draw->x0, draw->y1 - draw->y0);
132                         context->set_source_rgba (r, g, b, 0.25);
133                         context->fill ();
134                 }
135 #endif
136         }
137
138 }
139
140 ostream&
141 operator<< (ostream& o, Canvas& c)
142 {
143         c.dump (o);
144         return o;
145 }
146
147 std::string
148 Canvas::indent() const
149 {
150         string s;
151
152         for (int n = 0; n < ArdourCanvas::dump_depth; ++n) {
153                 s += '\t';
154         }
155
156         return s;
157 }
158
159 std::string
160 Canvas::render_indent() const
161 {
162         string s;
163
164         for (int n = 0; n < ArdourCanvas::render_depth; ++n) {
165                 s += ' ';
166         }
167
168         return s;
169 }
170
171 void
172 Canvas::dump (ostream& o) const
173 {
174         dump_depth = 0;
175         _root.dump (o);
176 }
177
178 /** Called when an item has been shown or hidden.
179  *  @param item Item that has been shown or hidden.
180  */
181 void
182 Canvas::item_shown_or_hidden (Item* item)
183 {
184         boost::optional<Rect> bbox = item->bounding_box ();
185         if (bbox) {
186                 if (item->item_to_window (*bbox).intersection (visible_area ())) {
187                         queue_draw_item_area (item, bbox.get ());
188                 }
189         }
190 }
191
192 /** Called when an item has a change to its visual properties
193  *  that do NOT affect its bounding box.
194  *  @param item Item that has been modified.
195  */
196 void
197 Canvas::item_visual_property_changed (Item* item)
198 {
199         boost::optional<Rect> bbox = item->bounding_box ();
200         if (bbox) {
201                 if (item->item_to_window (*bbox).intersection (visible_area ())) {
202                         queue_draw_item_area (item, bbox.get ());
203                 }
204         }
205 }
206
207 /** Called when an item has changed, but not moved.
208  *  @param item Item that has changed.
209  *  @param pre_change_bounding_box The bounding box of item before the change,
210  *  in the item's coordinates.
211  */
212 void
213 Canvas::item_changed (Item* item, boost::optional<Rect> pre_change_bounding_box)
214 {
215
216         Rect window_bbox = visible_area ();
217
218         if (pre_change_bounding_box) {
219
220                 if (item->item_to_window (*pre_change_bounding_box).intersection (window_bbox)) {
221                         /* request a redraw of the item's old bounding box */
222                         queue_draw_item_area (item, pre_change_bounding_box.get ());
223                 }
224         }
225
226         boost::optional<Rect> post_change_bounding_box = item->bounding_box ();
227         if (post_change_bounding_box) {
228
229                 if (item->item_to_window (*post_change_bounding_box).intersection (window_bbox)) {
230                         /* request a redraw of the item's new bounding box */
231                         queue_draw_item_area (item, post_change_bounding_box.get ());
232                 }
233         }
234 }
235
236 Duple
237 Canvas::window_to_canvas (Duple const & d) const
238 {
239         ScrollGroup* best_group = 0;
240         ScrollGroup* sg = 0;
241
242         /* if the coordinates are negative, clamp to zero and find the item
243          * that covers that "edge" position.
244          */
245
246         Duple in_window (d);
247
248         if (in_window.x < 0) {
249                 in_window.x = 0;
250         }
251         if (in_window.y < 0) {
252                 in_window.y = 0;
253         }
254
255         for (list<ScrollGroup*>::const_iterator s = scrollers.begin(); s != scrollers.end(); ++s) {
256
257                 if ((*s)->covers_window (in_window)) {
258                         sg = *s;
259
260                         /* XXX January 22nd 2015: leaving this in place for now
261                          * but I think it fixes a bug that really should be
262                          * fixed in a different way (and will be) by my next
263                          * commit. But it may still be relevant.
264                          */
265
266                         /* If scroll groups overlap, choose the one with the highest sensitivity,
267                            that is, choose an HV scroll group over an H or V
268                            only group.
269                         */
270                         if (!best_group || sg->sensitivity() > best_group->sensitivity()) {
271                                 best_group = sg;
272                                 if (sg->sensitivity() == (ScrollGroup::ScrollsVertically | ScrollGroup::ScrollsHorizontally)) {
273                                         /* Can't do any better than this. */
274                                         break;
275                                 }
276                         }
277                 }
278         }
279
280         if (best_group) {
281                 return d.translate (best_group->scroll_offset());
282         }
283
284         return d;
285 }
286
287 Duple
288 Canvas::canvas_to_window (Duple const & d, bool rounded) const
289 {
290         /* Find the scroll group that covers d (a canvas coordinate). Scroll groups are only allowed
291          * as children of the root group, so we just scan its first level
292          * children and see what we can find.
293          */
294
295         std::list<Item*> const& root_children (_root.items());
296         ScrollGroup* sg = 0;
297         Duple wd;
298
299         for (std::list<Item*>::const_iterator i = root_children.begin(); i != root_children.end(); ++i) {
300                 if (((sg = dynamic_cast<ScrollGroup*>(*i)) != 0) && sg->covers_canvas (d)) {
301                         break;
302                 }
303         }
304
305         if (sg) {
306                 wd = d.translate (-sg->scroll_offset());
307         } else {
308                 wd = d;
309         }
310
311         /* Note that this intentionally almost always returns integer coordinates */
312
313         if (rounded) {
314                 wd.x = round (wd.x);
315                 wd.y = round (wd.y);
316         }
317
318         return wd;
319 }
320
321 /** Called when an item has moved.
322  *  @param item Item that has moved.
323  *  @param pre_change_parent_bounding_box The bounding box of the item before
324  *  the move, in its parent's coordinates.
325  */
326 void
327 Canvas::item_moved (Item* item, boost::optional<Rect> pre_change_parent_bounding_box)
328 {
329         if (pre_change_parent_bounding_box) {
330                 /* request a redraw of where the item used to be. The box has
331                  * to be in parent coordinate space since the bounding box of
332                  * an item does not change when moved. If we use
333                  * item->item_to_canvas() on the old bounding box, we will be
334
335                  * using the item's new position, and so will compute the wrong
336                  * invalidation area. If we use the parent (which has not
337                  * moved, then this will work.
338                  */
339                 queue_draw_item_area (item->parent(), pre_change_parent_bounding_box.get ());
340         }
341
342         boost::optional<Rect> post_change_bounding_box = item->bounding_box ();
343         if (post_change_bounding_box) {
344                 /* request a redraw of where the item now is */
345                 queue_draw_item_area (item, post_change_bounding_box.get ());
346         }
347 }
348
349 /** Request a redraw of a particular area in an item's coordinates.
350  *  @param item Item.
351  *  @param area Area to redraw in the item's coordinates.
352  */
353 void
354 Canvas::queue_draw_item_area (Item* item, Rect area)
355 {
356         request_redraw (item->item_to_window (area));
357 }
358
359 void
360 Canvas::set_tooltip_timeout (uint32_t msecs)
361 {
362         tooltip_timeout_msecs = msecs;
363 }
364
365 void
366 Canvas::set_background_color (Color c)
367 {
368         _bg_color = c;
369
370         boost::optional<Rect> r = _root.bounding_box();
371
372         if (r) {
373                 request_redraw (_root.item_to_window (r.get()));
374         }
375 }
376
377 void
378 GtkCanvas::re_enter ()
379 {
380         DEBUG_TRACE (PBD::DEBUG::CanvasEnterLeave, "re-enter canvas by request\n");
381         _current_item = 0;
382         pick_current_item (0);
383 }
384
385 /** Construct a GtkCanvas */
386 GtkCanvas::GtkCanvas ()
387         : _current_item (0)
388         , _new_current_item (0)
389         , _grabbed_item (0)
390         , _focused_item (0)
391         , _single_exposure (1)
392         , current_tooltip_item (0)
393         , tooltip_window (0)
394         , _in_dtor (false)
395 {
396         /* these are the events we want to know about */
397         add_events (Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK |
398                     Gdk::SCROLL_MASK | Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK |
399                     Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK);
400 }
401
402 void
403 GtkCanvas::pick_current_item (int state)
404 {
405         int x;
406         int y;
407
408         /* this version of ::pick_current_item() is called after an item is
409          * added or removed, so we have no coordinates to work from as is the
410          * case with a motion event. Find out where the mouse is and use that.
411          */
412
413         Glib::RefPtr<const Gdk::Window> pointer_window = Gdk::Display::get_default()->get_window_at_pointer (x, y);
414
415         if (pointer_window != get_window()) {
416                 return;
417         }
418
419         pick_current_item (Duple (x, y), state);
420 }
421
422 /** Given @param point (a position in window coordinates)
423  *  and mouse state @param state, check to see if _current_item
424  *  (which will be used to deliver events) should change.
425  */
426 void
427 GtkCanvas::pick_current_item (Duple const & point, int state)
428 {
429         /* we do not enter/leave items during a drag/grab */
430
431         if (_grabbed_item) {
432                 return;
433         }
434
435         /* find the items at the given window position */
436
437         vector<Item const *> items;
438         _root.add_items_at_point (point, items);
439
440         DEBUG_TRACE (PBD::DEBUG::CanvasEnterLeave, string_compose ("%1 covers %2 items\n", point, items.size()));
441
442 #ifndef NDEBUG
443         if (DEBUG_ENABLED(PBD::DEBUG::CanvasEnterLeave)) {
444                 for (vector<Item const*>::const_iterator it = items.begin(); it != items.end(); ++it) {
445 #ifdef CANVAS_DEBUG
446                         std::cerr << "\tItem " << (*it)->whatami() << '/' << (*it)->name << " ignore events ? " << (*it)->ignore_events() << " vis ? " << (*it)->visible() << std::endl;
447 #else
448                         std::cerr << "\tItem " << (*it)->whatami() << '/' << " ignore events ? " << (*it)->ignore_events() << " vis ? " << (*it)->visible() << std::endl;
449 #endif
450                 }
451         }
452 #endif
453
454         /* put all items at point that are event-sensitive and visible and NOT
455            groups into within_items. Note that items is sorted from bottom to
456            top, but we're going to reverse that for within_items so that its
457            first item is the upper-most item that can be chosen as _current_item.
458         */
459
460         vector<Item const *>::const_iterator i;
461         list<Item const *> within_items;
462
463         for (i = items.begin(); i != items.end(); ++i) {
464
465                 Item const * possible_item = *i;
466
467                 /* We ignore invisible items, containers and items that ignore events */
468
469                 if (!possible_item->visible() || possible_item->ignore_events() || dynamic_cast<ArdourCanvas::Container const *>(possible_item) != 0) {
470                         continue;
471                 }
472                 within_items.push_front (possible_item);
473         }
474
475         DEBUG_TRACE (PBD::DEBUG::CanvasEnterLeave, string_compose ("after filtering insensitive + containers, we have  %1 items\n", within_items.size()));
476
477         if (within_items.empty()) {
478
479                 /* no items at point, just send leave event below */
480                 _new_current_item = 0;
481
482         } else {
483
484                 if (within_items.front() == _current_item) {
485                         /* uppermost item at point is already _current_item */
486                         DEBUG_TRACE (PBD::DEBUG::CanvasEnterLeave, string_compose ("CURRENT ITEM %1/%2\n", _new_current_item->whatami(), _current_item->name));
487                         return;
488                 }
489
490                 _new_current_item = const_cast<Item*> (within_items.front());
491         }
492
493         if (_new_current_item != _current_item) {
494                 deliver_enter_leave (point, state);
495         }
496
497         if (_current_item) {
498                 DEBUG_TRACE (PBD::DEBUG::CanvasEnterLeave, string_compose ("CURRENT ITEM %1/%2\n", _new_current_item->whatami(), _current_item->name));
499         } else {
500                 DEBUG_TRACE (PBD::DEBUG::CanvasEnterLeave, "--- no current item\n");
501         }
502
503 }
504
505 /** Deliver a series of enter & leave events based on the pointer position being at window
506  * coordinate @param point, and pointer @param state (modifier keys, etc)
507  */
508 void
509 GtkCanvas::deliver_enter_leave (Duple const & point, int state)
510 {
511         /* setup enter & leave event structures */
512
513         Glib::RefPtr<Gdk::Window> win = get_window();
514
515         if (!win) {
516                 return;
517         }
518
519         GdkEventCrossing enter_event;
520         enter_event.type = GDK_ENTER_NOTIFY;
521         enter_event.window = win->gobj();
522         enter_event.send_event = 0;
523         enter_event.subwindow = 0;
524         enter_event.mode = GDK_CROSSING_NORMAL;
525         enter_event.focus = FALSE;
526         enter_event.state = state;
527
528         /* Events delivered to canvas items are expected to be in canvas
529          * coordinates but @param point is in window coordinates.
530          */
531
532         Duple c = window_to_canvas (point);
533         enter_event.x = c.x;
534         enter_event.y = c.y;
535
536         GdkEventCrossing leave_event = enter_event;
537         leave_event.type = GDK_LEAVE_NOTIFY;
538
539         Item* i;
540         GdkNotifyType enter_detail = GDK_NOTIFY_UNKNOWN;
541         GdkNotifyType leave_detail = GDK_NOTIFY_UNKNOWN;
542         vector<Item*> items_to_leave_virtual;
543         vector<Item*> items_to_enter_virtual;
544
545         if (_new_current_item == 0) {
546
547                 leave_detail = GDK_NOTIFY_UNKNOWN;
548
549                 if (_current_item) {
550
551                         /* no current item, so also send virtual leave events to the
552                          * entire heirarchy for the current item
553                          */
554
555                         for (i = _current_item->parent(); i ; i = i->parent()) {
556                                 items_to_leave_virtual.push_back (i);
557                         }
558                 }
559
560         } else if (_current_item == 0) {
561
562                 enter_detail = GDK_NOTIFY_UNKNOWN;
563
564                 /* no current item, so also send virtual enter events to the
565                  * entire heirarchy for the new item
566                  */
567
568                 for (i = _new_current_item->parent(); i ; i = i->parent()) {
569                         items_to_enter_virtual.push_back (i);
570                 }
571
572         } else if (_current_item->is_descendant_of (*_new_current_item)) {
573
574                 /* move from descendant to ancestor (X: "_current_item is an
575                  * inferior ("child") of _new_current_item")
576                  *
577                  * Deliver "virtual" leave notifications to all items in the
578                  * heirarchy between current and new_current.
579                  */
580
581                 for (i = _current_item->parent(); i && i != _new_current_item; i = i->parent()) {
582                         items_to_leave_virtual.push_back (i);
583                 }
584
585                 enter_detail = GDK_NOTIFY_INFERIOR;
586                 leave_detail = GDK_NOTIFY_ANCESTOR;
587
588         } else if (_new_current_item->is_descendant_of (*_current_item)) {
589                 /* move from ancestor to descendant (X: "_new_current_item is
590                  * an inferior ("child") of _current_item")
591                  *
592                  * Deliver "virtual" enter notifications to all items in the
593                  * heirarchy between current and new_current.
594                  */
595
596                 for (i = _new_current_item->parent(); i && i != _current_item; i = i->parent()) {
597                         items_to_enter_virtual.push_back (i);
598                 }
599
600                 enter_detail = GDK_NOTIFY_ANCESTOR;
601                 leave_detail = GDK_NOTIFY_INFERIOR;
602
603         } else {
604
605                 Item const * common_ancestor = _current_item->closest_ancestor_with (*_new_current_item);
606
607                 /* deliver virtual leave events to everything between _current
608                  * and common_ancestor.
609                  */
610
611                 for (i = _current_item->parent(); i && i != common_ancestor; i = i->parent()) {
612                         items_to_leave_virtual.push_back (i);
613                 }
614
615                 /* deliver virtual enter events to everything between
616                  * _new_current and common_ancestor.
617                  */
618
619                 for (i = _new_current_item->parent(); i && i != common_ancestor; i = i->parent()) {
620                         items_to_enter_virtual.push_back (i);
621                 }
622
623                 enter_detail = GDK_NOTIFY_NONLINEAR;
624                 leave_detail = GDK_NOTIFY_NONLINEAR;
625         }
626
627
628         if (_current_item && !_current_item->ignore_events ()) {
629                 leave_event.detail = leave_detail;
630                 _current_item->Event ((GdkEvent*)&leave_event);
631                 DEBUG_TRACE (PBD::DEBUG::CanvasEnterLeave, string_compose ("LEAVE %1/%2\n", _current_item->whatami(), _current_item->name));
632         }
633
634         leave_event.detail = GDK_NOTIFY_VIRTUAL;
635         enter_event.detail = GDK_NOTIFY_VIRTUAL;
636
637         for (vector<Item*>::iterator it = items_to_leave_virtual.begin(); it != items_to_leave_virtual.end(); ++it) {
638                 if (!(*it)->ignore_events()) {
639                         DEBUG_TRACE (PBD::DEBUG::CanvasEnterLeave, string_compose ("leave %1/%2\n", (*it)->whatami(), (*it)->name));
640                         (*it)->Event ((GdkEvent*)&leave_event);
641                 }
642         }
643
644         for (vector<Item*>::iterator it = items_to_enter_virtual.begin(); it != items_to_enter_virtual.end(); ++it) {
645                 if (!(*it)->ignore_events()) {
646                         DEBUG_TRACE (PBD::DEBUG::CanvasEnterLeave, string_compose ("enter %1/%2\n", (*it)->whatami(), (*it)->name));
647                         (*it)->Event ((GdkEvent*)&enter_event);
648                         // std::cerr << "enter " << (*it)->whatami() << '/' << (*it)->name << std::endl;
649                 }
650         }
651
652         if (_new_current_item && !_new_current_item->ignore_events()) {
653                 enter_event.detail = enter_detail;
654                 DEBUG_TRACE (PBD::DEBUG::CanvasEnterLeave, string_compose ("ENTER %1/%2\n", _new_current_item->whatami(), _new_current_item->name));
655                 start_tooltip_timeout (_new_current_item);
656                 _new_current_item->Event ((GdkEvent*)&enter_event);
657         }
658
659         _current_item = _new_current_item;
660 }
661
662
663 /** Deliver an event to the appropriate item; either the grabbed item, or
664  *  one of the items underneath the event.
665  *  @param point Position that the event has occurred at, in canvas coordinates.
666  *  @param event The event.
667  */
668 bool
669 GtkCanvas::deliver_event (GdkEvent* event)
670 {
671         /* Point in in canvas coordinate space */
672
673         const Item* event_item;
674
675         if (_grabbed_item) {
676                 /* we have a grabbed item, so everything gets sent there */
677                 DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("%1 %2 (%3) was grabbed, send event there\n",
678                                                                        _grabbed_item, _grabbed_item->whatami(), _grabbed_item->name));
679                 event_item = _grabbed_item;
680         } else {
681                 event_item = _current_item;
682         }
683
684         if (!event_item) {
685                 return false;
686         }
687
688         /* run through the items from child to parent, until one claims the event */
689
690         Item* item = const_cast<Item*> (event_item);
691
692         while (item) {
693
694                 Item* parent = item->parent ();
695
696                 if (!item->ignore_events () &&
697                     item->Event (event)) {
698                         /* this item has just handled the event */
699                         DEBUG_TRACE (
700                                 PBD::DEBUG::CanvasEvents,
701                                 string_compose ("canvas event handled by %1 %2\n", item->whatami(), item->name.empty() ? "[unknown]" : item->name)
702                                 );
703
704                         return true;
705                 }
706
707                 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)));
708
709                 if ((item = parent) == 0) {
710                         break;
711                 }
712
713         }
714
715         return false;
716 }
717
718 /** Called when an item is being destroyed.
719  *  @param item Item being destroyed.
720  *  @param bounding_box Last known bounding box of the item.
721  */
722 void
723 GtkCanvas::item_going_away (Item* item, boost::optional<Rect> bounding_box)
724 {
725         if (bounding_box) {
726                 queue_draw_item_area (item, bounding_box.get ());
727         }
728
729         if (_new_current_item == item) {
730                 _new_current_item = 0;
731         }
732
733         if (_grabbed_item == item) {
734                 _grabbed_item = 0;
735         }
736
737         if (_focused_item == item) {
738                 _focused_item = 0;
739         }
740
741         if (current_tooltip_item) {
742                 current_tooltip_item = 0;
743                 stop_tooltip_timeout ();
744         }
745
746         ScrollGroup* sg = dynamic_cast<ScrollGroup*>(item);
747         if (sg) {
748                 scrollers.remove (sg);
749         }
750
751         if (_current_item == item) {
752                 /* no need to send a leave event to this item, since it is going away
753                  */
754                 _current_item = 0;
755                 pick_current_item (0); // no mouse state
756         }
757
758 }
759
760 void
761 GtkCanvas::on_size_allocate (Gtk::Allocation& a)
762 {
763         EventBox::on_size_allocate (a);
764 #ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
765         if (getenv("ARDOUR_IMAGE_SURFACE")) {
766 #endif
767 #if defined USE_CAIRO_IMAGE_SURFACE || defined OPTIONAL_CAIRO_IMAGE_SURFACE
768         /* allocate an image surface as large as the canvas itself */
769
770         canvas_image.clear ();
771         canvas_image = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, a.get_width(), a.get_height());
772 #endif
773 #ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
774         }
775 #endif
776 }
777
778 /** Handler for GDK expose events.
779  *  @param ev Event.
780  *  @return true if the event was handled.
781  */
782 bool
783 GtkCanvas::on_expose_event (GdkEventExpose* ev)
784 {
785         if (_in_dtor) {
786                 return true;
787         }
788
789 #ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
790         Cairo::RefPtr<Cairo::Context> draw_context;
791         Cairo::RefPtr<Cairo::Context> window_context;
792         if (getenv("ARDOUR_IMAGE_SURFACE")) {
793                 if (!canvas_image) {
794                         canvas_image = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, get_width(), get_height());
795                 }
796                 draw_context = Cairo::Context::create (canvas_image);
797                 window_context = get_window()->create_cairo_context ();
798         } else {
799                 draw_context = get_window()->create_cairo_context ();
800         }
801 #elif defined USE_CAIRO_IMAGE_SURFACE
802         if (!canvas_image) {
803                 canvas_image = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, get_width(), get_height());
804         }
805         Cairo::RefPtr<Cairo::Context> draw_context = Cairo::Context::create (canvas_image);
806         Cairo::RefPtr<Cairo::Context> window_context = get_window()->create_cairo_context ();
807 #else
808         Cairo::RefPtr<Cairo::Context> draw_context = get_window()->create_cairo_context ();
809 #endif
810
811         /* draw background color */
812
813         draw_context->rectangle (ev->area.x, ev->area.y, ev->area.width, ev->area.height);
814         draw_context->clip_preserve ();
815         set_source_rgba (draw_context, _bg_color);
816         draw_context->fill ();
817
818         /* render canvas */
819                 if ( _single_exposure ) {
820
821                         render (Rect (ev->area.x, ev->area.y, ev->area.x + ev->area.width, ev->area.y + ev->area.height), draw_context);
822
823                 } else {
824                         GdkRectangle* rects;
825                         gint nrects;
826
827                         gdk_region_get_rectangles (ev->region, &rects, &nrects);
828                         for (gint n = 0; n < nrects; ++n) {
829                                 draw_context->set_identity_matrix();  //reset the cairo matrix, just in case someone left it transformed after drawing ( cough )
830                                 render (Rect (rects[n].x, rects[n].y, rects[n].x + rects[n].width, rects[n].y + rects[n].height), draw_context);
831                         }
832                         g_free (rects);
833                 }
834
835 #ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
836         if (getenv("ARDOUR_IMAGE_SURFACE")) {
837 #endif
838 #if defined USE_CAIRO_IMAGE_SURFACE || defined OPTIONAL_CAIRO_IMAGE_SURFACE
839         /* now blit our private surface back to the GDK one */
840
841         window_context->rectangle (ev->area.x, ev->area.y, ev->area.width, ev->area.height);
842         window_context->clip ();
843         window_context->set_source (canvas_image, 0, 0);
844         window_context->set_operator (Cairo::OPERATOR_SOURCE);
845         window_context->paint ();
846 #endif
847 #ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
848         }
849 #endif
850
851         return true;
852 }
853
854 /** Handler for GDK scroll events.
855  *  @param ev Event.
856  *  @return true if the event was handled.
857  */
858 bool
859 GtkCanvas::on_scroll_event (GdkEventScroll* ev)
860 {
861         /* translate event coordinates from window to canvas */
862
863         GdkEvent copy = *((GdkEvent*)ev);
864         Duple winpos = Duple (ev->x, ev->y);
865         Duple where = window_to_canvas (winpos);
866
867         pick_current_item (winpos, ev->state);
868
869         copy.button.x = where.x;
870         copy.button.y = where.y;
871
872         /* Coordinates in the event will be canvas coordinates, correctly adjusted
873            for scroll if this GtkCanvas is in a GtkCanvasViewport.
874         */
875
876         DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("canvas scroll @ %1, %2 => %3\n", ev->x, ev->y, where));
877         return deliver_event (reinterpret_cast<GdkEvent*>(&copy));
878 }
879
880 /** Handler for GDK key press events.
881  *  @param ev Event.
882  *  @return true if the event was handled.
883  */
884 bool
885 GtkCanvas::on_key_press_event (GdkEventKey* ev)
886 {
887         DEBUG_TRACE (PBD::DEBUG::CanvasEvents, "canvas key press\n");
888         return deliver_event (reinterpret_cast<GdkEvent*>(ev));
889 }
890
891 /** Handler for GDK key release events.
892  *  @param ev Event.
893  *  @return true if the event was handled.
894  */
895 bool
896 GtkCanvas::on_key_release_event (GdkEventKey* ev)
897 {
898         DEBUG_TRACE (PBD::DEBUG::CanvasEvents, "canvas key release\n");
899         return deliver_event (reinterpret_cast<GdkEvent*>(ev));
900 }
901
902 /** Handler for GDK button press events.
903  *  @param ev Event.
904  *  @return true if the event was handled.
905  */
906 bool
907 GtkCanvas::on_button_press_event (GdkEventButton* ev)
908 {
909         /* translate event coordinates from window to canvas */
910
911         GdkEvent copy = *((GdkEvent*)ev);
912         Duple winpos = Duple (ev->x, ev->y);
913         Duple where = window_to_canvas (winpos);
914
915         pick_current_item (winpos, ev->state);
916
917         copy.button.x = where.x;
918         copy.button.y = where.y;
919
920         /* Coordinates in the event will be canvas coordinates, correctly adjusted
921            for scroll if this GtkCanvas is in a GtkCanvasViewport.
922         */
923
924         DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("canvas button press %1 @ %2, %3 => %4\n", ev->button, ev->x, ev->y, where));
925         return deliver_event (reinterpret_cast<GdkEvent*>(&copy));
926 }
927
928 /** Handler for GDK button release events.
929  *  @param ev Event.
930  *  @return true if the event was handled.
931  */
932 bool
933 GtkCanvas::on_button_release_event (GdkEventButton* ev)
934 {
935         /* translate event coordinates from window to canvas */
936
937         GdkEvent copy = *((GdkEvent*)ev);
938         Duple winpos = Duple (ev->x, ev->y);
939         Duple where = window_to_canvas (winpos);
940
941         pick_current_item (winpos, ev->state);
942
943         copy.button.x = where.x;
944         copy.button.y = where.y;
945
946         /* Coordinates in the event will be canvas coordinates, correctly adjusted
947            for scroll if this GtkCanvas is in a GtkCanvasViewport.
948         */
949
950         DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("canvas button release %1 @ %2, %3 => %4\n", ev->button, ev->x, ev->y, where));
951         return deliver_event (reinterpret_cast<GdkEvent*>(&copy));
952 }
953
954 bool
955 GtkCanvas::get_mouse_position (Duple& winpos) const
956 {
957         int x;
958         int y;
959         Gdk::ModifierType mask;
960         Glib::RefPtr<Gdk::Window> self = Glib::RefPtr<Gdk::Window>::cast_const (get_window ());
961
962         if (!self) {
963                 std::cerr << " no self window\n";
964                 winpos = Duple (0, 0);
965                 return false;
966         }
967
968         Glib::RefPtr<Gdk::Window> win = self->get_pointer (x, y, mask);
969
970         winpos.x = x;
971         winpos.y = y;
972
973         return true;
974 }
975
976 /** Handler for GDK motion events.
977  *  @param ev Event.
978  *  @return true if the event was handled.
979  */
980 bool
981 GtkCanvas::on_motion_notify_event (GdkEventMotion* ev)
982 {
983         hide_tooltip ();
984
985         /* translate event coordinates from window to canvas */
986
987         GdkEvent copy = *((GdkEvent*)ev);
988         Duple point (ev->x, ev->y);
989         Duple where = window_to_canvas (point);
990
991         copy.motion.x = where.x;
992         copy.motion.y = where.y;
993
994         /* Coordinates in "copy" will be canvas coordinates,
995         */
996
997         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));
998
999         MouseMotion (point); /* EMIT SIGNAL */
1000
1001         pick_current_item (point, ev->state);
1002
1003         /* Now deliver the motion event.  It may seem a little inefficient
1004            to recompute the items under the event, but the enter notify/leave
1005            events may have deleted canvas items so it is important to
1006            recompute the list in deliver_event.
1007         */
1008
1009         return deliver_event (reinterpret_cast<GdkEvent*> (&copy));
1010 }
1011
1012 bool
1013 GtkCanvas::on_enter_notify_event (GdkEventCrossing* ev)
1014 {
1015         pick_current_item (Duple (ev->x, ev->y), ev->state);
1016         return true;
1017 }
1018
1019 bool
1020 GtkCanvas::on_leave_notify_event (GdkEventCrossing* ev)
1021 {
1022         switch (ev->detail) {
1023         case GDK_NOTIFY_ANCESTOR:
1024         case GDK_NOTIFY_UNKNOWN:
1025         case GDK_NOTIFY_VIRTUAL:
1026         case GDK_NOTIFY_NONLINEAR:
1027         case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1028                 /* leaving window, cancel any tooltips */
1029                 stop_tooltip_timeout ();
1030                 hide_tooltip ();
1031                 break;
1032         default:
1033                 /* we don't care about any other kind
1034                    of leave event (notably GDK_NOTIFY_INFERIOR)
1035                 */
1036                 break;
1037         }
1038         _new_current_item = 0;
1039         deliver_enter_leave (Duple (ev->x, ev->y), ev->state);
1040         return true;
1041 }
1042
1043 /** Called to request a redraw of our canvas.
1044  *  @param area Area to redraw, in window coordinates.
1045  */
1046 void
1047 GtkCanvas::request_redraw (Rect const & request)
1048 {
1049         if (_in_dtor) {
1050                 return;
1051         }
1052
1053         Rect real_area;
1054
1055         Coord const w = width ();
1056         Coord const h = height ();
1057
1058         /* clamp area requested to actual visible window */
1059
1060         real_area.x0 = max (0.0, min (w, request.x0));
1061         real_area.x1 = max (0.0, min (w, request.x1));
1062         real_area.y0 = max (0.0, min (h, request.y0));
1063         real_area.y1 = max (0.0, min (h, request.y1));
1064
1065         queue_draw_area (real_area.x0, real_area.y0, real_area.width(), real_area.height());
1066 }
1067
1068 /** Called to request that we try to get a particular size for ourselves.
1069  *  @param size Size to request, in pixels.
1070  */
1071 void
1072 GtkCanvas::request_size (Duple size)
1073 {
1074         Duple req = size;
1075
1076         if (req.x > INT_MAX) {
1077                 req.x = INT_MAX;
1078         }
1079
1080         if (req.y > INT_MAX) {
1081                 req.y = INT_MAX;
1082         }
1083
1084         set_size_request (req.x, req.y);
1085 }
1086
1087 /** `Grab' an item, so that all events are sent to that item until it is `ungrabbed'.
1088  *  This is typically used for dragging items around, so that they are grabbed during
1089  *  the drag.
1090  *  @param item Item to grab.
1091  */
1092 void
1093 GtkCanvas::grab (Item* item)
1094 {
1095         /* XXX: should this be doing gdk_pointer_grab? */
1096         _grabbed_item = item;
1097 }
1098
1099
1100 /** `Ungrab' any item that was previously grabbed */
1101 void
1102 GtkCanvas::ungrab ()
1103 {
1104         /* XXX: should this be doing gdk_pointer_ungrab? */
1105         _grabbed_item = 0;
1106 }
1107
1108 /** Set keyboard focus on an item, so that all keyboard events are sent to that item until the focus
1109  *  moves elsewhere.
1110  *  @param item Item to grab.
1111  */
1112 void
1113 GtkCanvas::focus (Item* item)
1114 {
1115         _focused_item = item;
1116 }
1117
1118 void
1119 GtkCanvas::unfocus (Item* item)
1120 {
1121         if (item == _focused_item) {
1122                 _focused_item = 0;
1123         }
1124 }
1125
1126 /** @return The visible area of the canvas, in window coordinates */
1127 Rect
1128 GtkCanvas::visible_area () const
1129 {
1130         return Rect (0, 0, get_allocation().get_width (), get_allocation().get_height ());
1131 }
1132
1133 Coord
1134 GtkCanvas::width() const
1135 {
1136         return get_allocation().get_width();
1137 }
1138
1139 Coord
1140 GtkCanvas::height() const
1141 {
1142         return get_allocation().get_height();
1143 }
1144
1145 void
1146 GtkCanvas::start_tooltip_timeout (Item* item)
1147 {
1148         stop_tooltip_timeout ();
1149
1150         if (item && Gtkmm2ext::PersistentTooltip::tooltips_enabled ()) {
1151                 current_tooltip_item = item;
1152
1153                 /* wait for the first idle that happens after this is
1154                    called. this means that we've stopped processing events, which
1155                    in turn implies that the user has stopped doing stuff for a
1156                    little while.
1157                 */
1158
1159                 Glib::signal_idle().connect (sigc::mem_fun (*this, &GtkCanvas::really_start_tooltip_timeout));
1160         }
1161 }
1162
1163 bool
1164 GtkCanvas::really_start_tooltip_timeout ()
1165 {
1166         /* an idle has occurred since we entered a tooltip-bearing widget. Now
1167          * wait 1 second and if the timeout isn't cancelled, show the tooltip.
1168          */
1169
1170         if (current_tooltip_item) {
1171                 tooltip_timeout_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &GtkCanvas::show_tooltip), tooltip_timeout_msecs);
1172         }
1173
1174         return false; /* this is called from an idle callback, don't call it again */
1175 }
1176
1177 void
1178 GtkCanvas::stop_tooltip_timeout ()
1179 {
1180         current_tooltip_item = 0;
1181         tooltip_timeout_connection.disconnect ();
1182 }
1183
1184 bool
1185 GtkCanvas::show_tooltip ()
1186 {
1187         Rect tooltip_item_bbox;
1188
1189         if (!current_tooltip_item || current_tooltip_item->tooltip().empty() || !current_tooltip_item->bounding_box()) {
1190                 return false;
1191         }
1192
1193         if (!tooltip_window) {
1194                 tooltip_window = new Gtk::Window (Gtk::WINDOW_POPUP);
1195                 tooltip_label = manage (new Gtk::Label);
1196                 tooltip_label->show ();
1197                 tooltip_window->add (*tooltip_label);
1198                 tooltip_window->set_border_width (1);
1199                 tooltip_window->set_name ("tooltip");
1200         }
1201
1202         tooltip_label->set_text (current_tooltip_item->tooltip());
1203
1204         /* figure out where to position the tooltip */
1205
1206         Gtk::Widget* toplevel = get_toplevel();
1207         assert (toplevel);
1208         int pointer_x, pointer_y;
1209         Gdk::ModifierType mask;
1210
1211         (void) toplevel->get_window()->get_pointer (pointer_x, pointer_y, mask);
1212
1213         Duple tooltip_window_origin (pointer_x, pointer_y);
1214
1215         /* convert to root window coordinates */
1216
1217         int win_x, win_y;
1218         dynamic_cast<Gtk::Window*>(toplevel)->get_position (win_x, win_y);
1219
1220         tooltip_window_origin = tooltip_window_origin.translate (Duple (win_x, win_y));
1221
1222         /* we don't want the pointer to be inside the window when it is
1223          * displayed, because then we generate a leave/enter event pair when
1224          * the window is displayed then hidden - the enter event will
1225          * trigger a new tooltip timeout.
1226          *
1227          * So move the window right of the pointer position by just a enough
1228          * to get it away from the pointer.
1229          */
1230
1231         tooltip_window_origin.x += 30;
1232         tooltip_window_origin.y += 45;
1233
1234         /* move the tooltip window into position */
1235
1236         tooltip_window->move (tooltip_window_origin.x, tooltip_window_origin.y);
1237
1238         /* ready to show */
1239
1240         tooltip_window->present ();
1241
1242         /* called from a timeout handler, don't call it again */
1243
1244         return false;
1245 }
1246
1247 void
1248 GtkCanvas::hide_tooltip ()
1249 {
1250         /* hide it if its there */
1251
1252         if (tooltip_window) {
1253                 tooltip_window->hide ();
1254
1255                 // Delete the tooltip window so it'll get re-created
1256                 // (i.e. properly re-sized) on the next usage.
1257                 delete tooltip_window;
1258                 tooltip_window = NULL;
1259         }
1260 }
1261
1262 /** Create a GtkCanvaSViewport.
1263  *  @param hadj Adjustment to use for horizontal scrolling.
1264  *  @param vadj Adjustment to use for vertica scrolling.
1265  */
1266 GtkCanvasViewport::GtkCanvasViewport (Gtk::Adjustment& hadj, Gtk::Adjustment& vadj)
1267         : Alignment (0, 0, 1.0, 1.0)
1268         , hadjustment (hadj)
1269         , vadjustment (vadj)
1270 {
1271         add (_canvas);
1272
1273         hadj.signal_value_changed().connect (sigc::mem_fun (*this, &GtkCanvasViewport::scrolled));
1274         vadj.signal_value_changed().connect (sigc::mem_fun (*this, &GtkCanvasViewport::scrolled));
1275 }
1276
1277 void
1278 GtkCanvasViewport::scrolled ()
1279 {
1280         _canvas.scroll_to (hadjustment.get_value(), vadjustment.get_value());
1281         queue_draw ();
1282 }
1283
1284 /** Handler for when GTK asks us what minimum size we want.
1285  *  @param req Requsition to fill in.
1286  */
1287 void
1288 GtkCanvasViewport::on_size_request (Gtk::Requisition* req)
1289 {
1290         /* force the canvas to size itself */
1291         // _canvas.root()->bounding_box();
1292
1293         req->width = 16;
1294         req->height = 16;
1295 }
1296