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