use shared_ptr<> for all region handling
[ardour.git] / libs / ardour / region.cc
1 /*
2     Copyright (C) 2000-2003 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18     $Id$
19 */
20
21 #include <iostream>
22 #include <cmath>
23 #include <climits>
24 #include <algorithm>
25
26 #include <sigc++/bind.h>
27 #include <sigc++/class_slot.h>
28
29 #include <glibmm/thread.h>
30 #include <pbd/xml++.h>
31
32 #include <ardour/region.h>
33 #include <ardour/playlist.h>
34 #include <ardour/session.h>
35
36 #include "i18n.h"
37
38 using namespace std;
39 using namespace ARDOUR;
40 using namespace PBD;
41
42 Change Region::FadeChanged       = ARDOUR::new_change ();
43 Change Region::SyncOffsetChanged = ARDOUR::new_change ();
44 Change Region::MuteChanged       = ARDOUR::new_change ();
45 Change Region::OpacityChanged    = ARDOUR::new_change ();
46 Change Region::LockChanged       = ARDOUR::new_change ();
47 Change Region::LayerChanged      = ARDOUR::new_change ();
48 Change Region::HiddenChanged     = ARDOUR::new_change ();
49
50 Region::Region (jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Region::Flag flags)
51 {
52         /* basic Region constructor */
53
54         _flags = flags;
55         _playlist = 0;
56         _read_data_count = 0;
57         _frozen = 0;
58         pending_changed = Change (0);
59
60         _name = name;
61         _start = start; 
62         _sync_position = _start;
63         _length = length; 
64         _position = 0; 
65         _layer = layer;
66         _current_state_id = 0;
67         _read_data_count = 0;
68         _first_edit = EditChangesNothing;
69         _last_layer_op = 0;
70 }
71
72 Region::Region (boost::shared_ptr<const Region> other, jack_nframes_t offset, jack_nframes_t length, const string& name, layer_t layer, Flag flags)
73 {
74         /* create a new Region from part of an existing one */
75
76         _frozen = 0;
77         pending_changed = Change (0);
78         _playlist = 0;
79         _read_data_count = 0;
80
81         _start = other->_start + offset; 
82         if (other->_sync_position < offset) {
83                 _sync_position = other->_sync_position;
84         } else {
85                 _sync_position = _start;
86         }
87         _length = length; 
88         _name = name;
89         _position = 0; 
90         _layer = layer; 
91         _flags = Flag (flags & ~(Locked|WholeFile|Hidden));
92         _current_state_id = 0;
93         _first_edit = EditChangesNothing;
94         _last_layer_op = 0;
95 }
96
97 Region::Region (boost::shared_ptr<const Region> other)
98 {
99         /* Pure copy constructor */
100
101         _frozen = 0;
102         pending_changed = Change (0);
103         _playlist = 0;
104         _read_data_count = 0;
105
106         _first_edit = EditChangesID;
107         other->_first_edit = EditChangesName;
108
109         if (other->_extra_xml) {
110                 _extra_xml = new XMLNode (*other->_extra_xml);
111         } else {
112                 _extra_xml = 0;
113         }
114
115         _start = other->_start;
116         _sync_position = other->_sync_position;
117         _length = other->_length; 
118         _name = other->_name;
119         _position = other->_position; 
120         _layer = other->_layer; 
121         _flags = Flag (other->_flags & ~Locked);
122         _current_state_id = 0;
123         _last_layer_op = other->_last_layer_op;
124 }
125
126 Region::Region (const XMLNode& node)
127 {
128         _frozen = 0;
129         pending_changed = Change (0);
130         _playlist = 0;
131         _read_data_count = 0;
132         _start = 0; 
133         _sync_position = _start;
134         _length = 0;
135         _name = X_("error: XML did not reset this");
136         _position = 0; 
137         _layer = 0;
138         _flags = Flag (0);
139         _current_state_id = 0;
140         _first_edit = EditChangesNothing;
141
142         if (set_state (node)) {
143                 throw failed_constructor();
144         }
145 }
146
147 Region::~Region ()
148 {
149         notify_callbacks ();
150
151         /* derived classes must emit GoingAway */
152 }
153
154 void
155 Region::set_playlist (Playlist* pl)
156 {
157         _playlist = pl;
158 }
159
160 void
161 Region::store_state (RegionState& state) const
162 {
163         state._start = _start;
164         state._length = _length;
165         state._position = _position;
166         state._flags = _flags;
167         state._sync_position = _sync_position;
168         state._layer = _layer;
169         state._name = _name;
170         state._first_edit = _first_edit;
171 }       
172
173 Change
174 Region::restore_and_return_flags (RegionState& state)
175 {
176         Change what_changed = Change (0);
177
178         {
179                 Glib::Mutex::Lock lm (lock);
180                 
181                 if (_start != state._start) {
182                         what_changed = Change (what_changed|StartChanged);      
183                         _start = state._start;
184                 }
185                 if (_length != state._length) {
186                         what_changed = Change (what_changed|LengthChanged);
187                         _length = state._length;
188                 }
189                 if (_position != state._position) {
190                         what_changed = Change (what_changed|PositionChanged);
191                         _position = state._position;
192                 } 
193                 if (_sync_position != state._sync_position) {
194                         _sync_position = state._sync_position;
195                         what_changed = Change (what_changed|SyncOffsetChanged);
196                 }
197                 if (_layer != state._layer) {
198                         what_changed = Change (what_changed|LayerChanged);
199                         _layer = state._layer;
200                 }
201
202                 uint32_t old_flags = _flags;
203                 _flags = Flag (state._flags);
204                 
205                 if ((old_flags ^ state._flags) & Muted) {
206                         what_changed = Change (what_changed|MuteChanged);
207                 }
208                 if ((old_flags ^ state._flags) & Opaque) {
209                         what_changed = Change (what_changed|OpacityChanged);
210                 }
211                 if ((old_flags ^ state._flags) & Locked) {
212                         what_changed = Change (what_changed|LockChanged);
213                 }
214
215                 _first_edit = state._first_edit;
216         }
217
218         return what_changed;
219 }
220
221 void
222 Region::set_name (string str)
223
224 {
225         if (_name != str) {
226                 _name = str; 
227                 send_change (NameChanged);
228         }
229 }
230
231 void
232 Region::set_length (jack_nframes_t len, void *src)
233 {
234         if (_flags & Locked) {
235                 return;
236         }
237
238         if (_length != len && len != 0) {
239
240                 if (!verify_length (len)) {
241                         return;
242                 }
243                 
244                 _length = len;
245
246                 _flags = Region::Flag (_flags & ~WholeFile);
247
248                 first_edit ();
249                 maybe_uncopy ();
250
251                 if (!_frozen) {
252                         recompute_at_end ();
253
254                         char buf[64];
255                         snprintf (buf, sizeof (buf), "length set to %u", len);
256                         save_state (buf);
257                 }
258
259                 send_change (LengthChanged);
260         }
261 }
262
263 void
264 Region::maybe_uncopy ()
265 {
266 }
267
268 void
269 Region::first_edit ()
270 {
271         if (_first_edit != EditChangesNothing && _playlist) {
272
273                 _name = _playlist->session().new_region_name (_name);
274                 _first_edit = EditChangesNothing;
275
276                 send_change (NameChanged);
277                 /// XXX CheckNewRegion (boost::shared_ptr<Region>(this));
278         }
279 }
280
281 void
282 Region::move_to_natural_position (void *src)
283 {
284         if (!_playlist) {
285                 return;
286         }
287
288         boost::shared_ptr<Region> whole_file_region = get_parent();
289
290         if (whole_file_region) {
291                 set_position (whole_file_region->position() + _start, src);
292         }
293 }
294         
295 void
296 Region::special_set_position (jack_nframes_t pos)
297 {
298         /* this is used when creating a whole file region as 
299            a way to store its "natural" or "captured" position.
300         */
301
302         _position = pos;
303 }
304
305 void
306 Region::set_position (jack_nframes_t pos, void *src)
307 {
308         if (_flags & Locked) {
309                 return;
310         }
311
312         if (_position != pos) {
313                 _position = pos;
314
315                 if (!_frozen) {
316                         char buf[64];
317                         snprintf (buf, sizeof (buf), "position set to %u", pos);
318                         save_state (buf);
319                 }
320         }
321
322         /* do this even if the position is the same. this helps out
323            a GUI that has moved its representation already.
324         */
325
326         send_change (PositionChanged);
327 }
328
329 void
330 Region::set_position_on_top (jack_nframes_t pos, void *src)
331 {
332         if (_flags & Locked) {
333                 return;
334         }
335
336         if (_position != pos) {
337                 _position = pos;
338
339                 if (!_frozen) {
340                         char buf[64];
341                         snprintf (buf, sizeof (buf), "position set to %u", pos);
342                         save_state (buf);
343                 }
344         }
345
346         _playlist->raise_region_to_top (boost::shared_ptr<Region>(this));
347
348         /* do this even if the position is the same. this helps out
349            a GUI that has moved its representation already.
350         */
351         
352         send_change (PositionChanged);
353 }
354
355 void
356 Region::nudge_position (long n, void *src)
357 {
358         if (_flags & Locked) {
359                 return;
360         }
361
362         if (n == 0) {
363                 return;
364         }
365         
366         if (n > 0) {
367                 if (_position > max_frames - n) {
368                         _position = max_frames;
369                 } else {
370                         _position += n;
371                 }
372         } else {
373                 if (_position < (jack_nframes_t) -n) {
374                         _position = 0;
375                 } else {
376                         _position += n;
377                 }
378         }
379
380         if (!_frozen) {
381                 char buf[64];
382                 snprintf (buf, sizeof (buf), "position set to %u", _position);
383                 save_state (buf);
384         }
385
386         send_change (PositionChanged);
387 }
388
389 void
390 Region::set_start (jack_nframes_t pos, void *src)
391 {
392         if (_flags & Locked) {
393                 return;
394         }
395         /* This just sets the start, nothing else. It effectively shifts
396            the contents of the Region within the overall extent of the Source,
397            without changing the Region's position or length
398         */
399
400         if (_start != pos) {
401
402                 if (!verify_start (pos)) {
403                         return;
404                 }
405
406                 _start = pos;
407                 _flags = Region::Flag (_flags & ~WholeFile);
408                 first_edit ();
409
410                 if (!_frozen) {
411                         char buf[64];
412                         snprintf (buf, sizeof (buf), "start set to %u", pos);
413                         save_state (buf);
414                 }
415
416                 send_change (StartChanged);
417         }
418 }
419
420 void
421 Region::trim_start (jack_nframes_t new_position, void *src)
422 {
423         if (_flags & Locked) {
424                 return;
425         }
426         jack_nframes_t new_start;
427         int32_t start_shift;
428         
429         if (new_position > _position) {
430                 start_shift = new_position - _position;
431         } else {
432                 start_shift = -(_position - new_position);
433         }
434
435         if (start_shift > 0) {
436
437                 if (_start > max_frames - start_shift) {
438                         new_start = max_frames;
439                 } else {
440                         new_start = _start + start_shift;
441                 }
442
443                 if (!verify_start (new_start)) {
444                         return;
445                 }
446
447         } else if (start_shift < 0) {
448
449                 if (_start < (jack_nframes_t) -start_shift) {
450                         new_start = 0;
451                 } else {
452                         new_start = _start + start_shift;
453                 }
454         } else {
455                 return;
456         }
457
458         if (new_start == _start) {
459                 return;
460         }
461         
462         _start = new_start;
463         _flags = Region::Flag (_flags & ~WholeFile);
464         first_edit ();
465
466         if (!_frozen) {
467                 char buf[64];
468                 snprintf (buf, sizeof (buf), "slipped start to %u", _start);
469                 save_state (buf);
470         }
471
472         send_change (StartChanged);
473 }
474
475 void
476 Region::trim_front (jack_nframes_t new_position, void *src)
477 {
478         if (_flags & Locked) {
479                 return;
480         }
481
482         jack_nframes_t end = _position + _length - 1;
483         jack_nframes_t source_zero;
484
485         if (_position > _start) {
486                 source_zero = _position - _start;
487         } else {
488                 source_zero = 0; // its actually negative, but this will work for us
489         }
490
491         if (new_position < end) { /* can't trim it zero or negative length */
492                 
493                 jack_nframes_t newlen;
494
495                 /* can't trim it back passed where source position zero is located */
496                 
497                 new_position = max (new_position, source_zero);
498                 
499                 
500                 if (new_position > _position) {
501                         newlen = _length - (new_position - _position);
502                 } else {
503                         newlen = _length + (_position - new_position);
504                 }
505                 
506                 trim_to_internal (new_position, newlen, src);
507                 if (!_frozen) {
508                         recompute_at_start ();
509                 }
510         }
511 }
512
513 void
514 Region::trim_end (jack_nframes_t new_endpoint, void *src)
515 {
516         if (_flags & Locked) {
517                 return;
518         }
519
520         if (new_endpoint > _position) {
521                 trim_to_internal (_position, new_endpoint - _position, this);
522                 if (!_frozen) {
523                         recompute_at_end ();
524                 }
525         }
526 }
527
528 void
529 Region::trim_to (jack_nframes_t position, jack_nframes_t length, void *src)
530 {
531         if (_flags & Locked) {
532                 return;
533         }
534
535         trim_to_internal (position, length, src);
536
537         if (!_frozen) {
538                 recompute_at_start ();
539                 recompute_at_end ();
540         }
541 }
542
543 void
544 Region::trim_to_internal (jack_nframes_t position, jack_nframes_t length, void *src)
545 {
546         int32_t start_shift;
547         jack_nframes_t new_start;
548
549         if (_flags & Locked) {
550                 return;
551         }
552
553         if (position > _position) {
554                 start_shift = position - _position;
555         } else {
556                 start_shift = -(_position - position);
557         }
558
559         if (start_shift > 0) {
560
561                 if (_start > max_frames - start_shift) {
562                         new_start = max_frames;
563                 } else {
564                         new_start = _start + start_shift;
565                 }
566
567
568         } else if (start_shift < 0) {
569
570                 if (_start < (jack_nframes_t) -start_shift) {
571                         new_start = 0;
572                 } else {
573                         new_start = _start + start_shift;
574                 }
575         } else {
576                 new_start = _start;
577         }
578
579         if (!verify_start_and_length (new_start, length)) {
580                 return;
581         }
582
583         Change what_changed = Change (0);
584
585         if (_start != new_start) {
586                 _start = new_start;
587                 what_changed = Change (what_changed|StartChanged);
588         }
589         if (_length != length) {
590                 _length = length;
591                 what_changed = Change (what_changed|LengthChanged);
592         }
593         if (_position != position) {
594                 _position = position;
595                 what_changed = Change (what_changed|PositionChanged);
596         }
597         
598         _flags = Region::Flag (_flags & ~WholeFile);
599
600         if (what_changed & (StartChanged|LengthChanged)) {
601                 first_edit ();
602         } 
603
604         if (what_changed) {
605                 
606                 if (!_frozen) {
607                         char buf[64];
608                         snprintf (buf, sizeof (buf), "trimmed to %u-%u", _position, _position+_length-1);
609                         save_state (buf);
610                 }
611
612                 send_change (what_changed);
613         }
614 }       
615
616 void
617 Region::set_hidden (bool yn)
618 {
619         if (hidden() != yn) {
620
621                 if (yn) {
622                         _flags = Flag (_flags|Hidden);
623                 } else {
624                         _flags = Flag (_flags & ~Hidden);
625                 }
626
627                 send_change (HiddenChanged);
628         }
629 }
630
631 void
632 Region::set_muted (bool yn)
633 {
634         if (muted() != yn) {
635
636                 if (yn) {
637                         _flags = Flag (_flags|Muted);
638                 } else {
639                         _flags = Flag (_flags & ~Muted);
640                 }
641
642                 if (!_frozen) {
643                         char buf[64];
644                         if (yn) {
645                                 snprintf (buf, sizeof (buf), "muted");
646                         } else {
647                                 snprintf (buf, sizeof (buf), "unmuted");
648                         }
649                         save_state (buf);
650                 }
651
652                 send_change (MuteChanged);
653         }
654 }
655
656 void
657 Region::set_opaque (bool yn)
658 {
659         if (opaque() != yn) {
660                 if (!_frozen) {
661                         char buf[64];
662                         if (yn) {
663                                 snprintf (buf, sizeof (buf), "opaque");
664                                 _flags = Flag (_flags|Opaque);
665                         } else {
666                                 snprintf (buf, sizeof (buf), "translucent");
667                                 _flags = Flag (_flags & ~Opaque);
668                         }
669                         save_state (buf);
670                 }
671                 send_change (OpacityChanged);
672         }
673 }
674
675 void
676 Region::set_locked (bool yn)
677 {
678         if (locked() != yn) {
679                 if (!_frozen) {
680                         char buf[64];
681                         if (yn) {
682                                 snprintf (buf, sizeof (buf), "locked");
683                                 _flags = Flag (_flags|Locked);
684                         } else {
685                                 snprintf (buf, sizeof (buf), "unlocked");
686                                 _flags = Flag (_flags & ~Locked);
687                         }
688                         save_state (buf);
689                 }
690                 send_change (LockChanged);
691         }
692 }
693
694 void
695 Region::set_sync_position (jack_nframes_t absolute_pos)
696 {
697         jack_nframes_t file_pos;
698
699         file_pos = _start + (absolute_pos - _position);
700
701         if (file_pos != _sync_position) {
702                 
703                 _sync_position = file_pos;
704                 _flags = Flag (_flags|SyncMarked);
705
706                 if (!_frozen) {
707                         char buf[64];
708                         maybe_uncopy ();
709                         snprintf (buf, sizeof (buf), "sync point set to %u", _sync_position);
710                         save_state (buf);
711                 }
712                 send_change (SyncOffsetChanged);
713         }
714 }
715
716 void
717 Region::clear_sync_position ()
718 {
719         if (_flags & SyncMarked) {
720                 _flags = Flag (_flags & ~SyncMarked);
721
722                 if (!_frozen) {
723                         maybe_uncopy ();
724                         save_state ("sync point removed");
725                 }
726                 send_change (SyncOffsetChanged);
727         }
728 }
729
730 jack_nframes_t
731 Region::sync_offset (int& dir) const
732 {
733         /* returns the sync point relative the first frame of the region */
734
735         if (_flags & SyncMarked) {
736                 if (_sync_position > _start) {
737                         dir = 1;
738                         return _sync_position - _start; 
739                 } else {
740                         dir = -1;
741                         return _start - _sync_position;
742                 }
743         } else {
744                 dir = 0;
745                 return 0;
746         }
747 }
748
749 jack_nframes_t 
750 Region::adjust_to_sync (jack_nframes_t pos)
751 {
752         int sync_dir;
753         jack_nframes_t offset = sync_offset (sync_dir);
754         
755         if (sync_dir > 0) {
756                 if (max_frames - pos > offset) {
757                         pos += offset;
758                 }
759         } else {
760                 if (pos > offset) {
761                         pos -= offset;
762                 } else {
763                         pos = 0;
764                 }
765         }
766
767         return pos;
768 }
769
770 jack_nframes_t
771 Region::sync_position() const
772 {
773         if (_flags & SyncMarked) {
774                 return _sync_position; 
775         } else {
776                 return _start;
777         }
778 }
779
780
781 void
782 Region::raise ()
783 {
784         if (_playlist == 0) {
785                 return;
786         }
787
788         _playlist->raise_region (boost::shared_ptr<Region>(this));
789 }
790
791 void
792 Region::lower ()
793 {
794         if (_playlist == 0) {
795                 return;
796         }
797
798         _playlist->lower_region (boost::shared_ptr<Region>(this));
799 }
800
801 void
802 Region::raise_to_top ()
803 {
804
805         if (_playlist == 0) {
806                 return;
807         }
808
809         _playlist->raise_region_to_top (boost::shared_ptr<Region>(this));
810 }
811
812 void
813 Region::lower_to_bottom ()
814 {
815         if (_playlist == 0) {
816                 return;
817         }
818
819         _playlist->lower_region_to_bottom (boost::shared_ptr<Region>(this));
820 }
821
822 void
823 Region::set_layer (layer_t l)
824 {
825         if (_layer != l) {
826                 _layer = l;
827                 
828                 if (!_frozen) {
829                         char buf[64];
830                         snprintf (buf, sizeof (buf), "layer set to %" PRIu32, _layer);
831                         save_state (buf);
832                 }
833                 
834                 send_change (LayerChanged);
835         }
836 }
837
838 XMLNode&
839 Region::state (bool full_state)
840 {
841         XMLNode *node = new XMLNode ("Region");
842         char buf[64];
843         
844         _id.print (buf);
845         node->add_property ("id", buf);
846         node->add_property ("name", _name);
847         snprintf (buf, sizeof (buf), "%u", _start);
848         node->add_property ("start", buf);
849         snprintf (buf, sizeof (buf), "%u", _length);
850         node->add_property ("length", buf);
851         snprintf (buf, sizeof (buf), "%u", _position);
852         node->add_property ("position", buf);
853
854         /* note: flags are stored by derived classes */
855
856         snprintf (buf, sizeof (buf), "%d", (int) _layer);
857         node->add_property ("layer", buf);
858         snprintf (buf, sizeof (buf), "%u", _sync_position);
859         node->add_property ("sync-position", buf);
860
861         return *node;
862 }
863
864 XMLNode&
865 Region::get_state ()
866 {
867         return state (true);
868 }
869
870 int
871 Region::set_state (const XMLNode& node)
872 {
873         const XMLNodeList& nlist = node.children();
874         const XMLProperty *prop;
875
876         if (_extra_xml) {
877                 delete _extra_xml;
878                 _extra_xml = 0;
879         }
880
881         if ((prop = node.property ("id")) == 0) {
882                 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
883                 return -1;
884         }
885
886         _id = prop->value();
887
888         if ((prop = node.property ("name")) == 0) {
889                 error << _("Session: XMLNode describing a Region is incomplete (no name)") << endmsg;
890                 return -1;
891         }
892
893         _name = prop->value();
894
895         if ((prop = node.property ("start")) != 0) {
896                 _start = (jack_nframes_t) atoi (prop->value().c_str());
897         }
898
899         if ((prop = node.property ("length")) != 0) {
900                 _length = (jack_nframes_t) atoi (prop->value().c_str());
901         }
902
903         if ((prop = node.property ("position")) != 0) {
904                 _position = (jack_nframes_t) atoi (prop->value().c_str());
905         }
906
907         if ((prop = node.property ("layer")) != 0) {
908                 _layer = (layer_t) atoi (prop->value().c_str());
909         }
910
911         /* note: derived classes set flags */
912
913         if ((prop = node.property ("sync-position")) != 0) {
914                 _sync_position = (jack_nframes_t) atoi (prop->value().c_str());
915         } else {
916                 _sync_position = _start;
917         }
918         
919         for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
920                 
921                 XMLNode *child;
922                 
923                 child = (*niter);
924                 
925                 if (child->name () == "extra") {
926                         _extra_xml = new XMLNode (*child);
927                         break;
928                 }
929         }
930
931         _first_edit = EditChangesNothing;
932
933         return 0;
934 }
935
936 void
937 Region::freeze ()
938 {
939         _frozen++;
940 }
941
942 void
943 Region::thaw (const string& why)
944 {
945         Change what_changed = Change (0);
946
947         {
948                 Glib::Mutex::Lock lm (lock);
949
950                 if (_frozen && --_frozen > 0) {
951                         return;
952                 }
953
954                 if (pending_changed) {
955                         what_changed = pending_changed;
956                         pending_changed = Change (0);
957                 }
958         }
959
960         if (what_changed == Change (0)) {
961                 return;
962         }
963
964         if (what_changed & LengthChanged) {
965                 if (what_changed & PositionChanged) {
966                         recompute_at_start ();
967                 } 
968                 recompute_at_end ();
969         }
970                 
971         save_state (why);
972         StateChanged (what_changed);
973 }
974
975 void
976 Region::send_change (Change what_changed)
977 {
978         {
979                 Glib::Mutex::Lock lm (lock);
980                 if (_frozen) {
981                         pending_changed = Change (pending_changed|what_changed);
982                         return;
983                 } 
984         }
985
986         StateManager::send_state_changed (what_changed);
987 }
988
989 void
990 Region::set_last_layer_op (uint64_t when)
991 {
992         _last_layer_op = when;
993 }
994
995 bool
996 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
997 {
998         return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
999 }
1000
1001 bool
1002 Region::equivalent (boost::shared_ptr<const Region> other) const
1003 {
1004         return _start == other->_start &&
1005                 _position == other->_position &&
1006                 _length == other->_length;
1007 }
1008
1009 bool
1010 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1011 {
1012         return _start == other->_start &&
1013                 _length == other->_length;
1014 }
1015
1016 bool
1017 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1018 {
1019         return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1020 }