gr.Clip ();
}
- lock (Children) {
- foreach (GraphicObject g in Children) {
- if (CurrentInterface.DragAndDropOperation?.DragSource == g)
- continue;
- g.Paint (ref gr);
- }
+ childrenRWLock.EnterReadLock ();
+
+ foreach (GraphicObject g in Children) {
+ if (CurrentInterface.DragAndDropOperation?.DragSource == g)
+ continue;
+ g.Paint (ref gr);
}
+ childrenRWLock.ExitReadLock ();
+
if (showDockingTarget) {
Rectangle r;
if (mainStack == null)
using Cairo;
using System.Diagnostics;
using Crow.IML;
+using System.Threading;
namespace Crow
{
/// </summary>
public class GraphicObject : ILayoutable, IValueChange, IDisposable
{
+ internal ReaderWriterLockSlim parentRWLock = new ReaderWriterLockSlim();
+
#region IDisposable implementation
protected bool disposed = false;
if (IsQueueForRedraw)
throw new Exception("Trying to dispose an object queued for Redraw: " + this.ToString());
#endif
+
if (CurrentInterface.HoverWidget != null) {
if (CurrentInterface.HoverWidget.IsOrIsInside(this))
CurrentInterface.HoverWidget = null;
}
if (!localDataSourceIsNull)
DataSource = null;
+
+ parentRWLock.EnterWriteLock();
parent = null;
+ parentRWLock.ExitWriteLock();
} else
Debug.WriteLine ("!!! Finalized by GC: {0}", this.ToString ());
Clipping?.Dispose ();
bmp?.Dispose ();
disposed = true;
-
}
#endregion
//TODO: we should ensure the whole parsed widget tree is the last painted
public Rectangle LastPaintedSlot;
/// <summary>Prevent requeuing multiple times the same widget</summary>
- public bool IsQueueForRedraw = false;
+ public bool IsQueueForClipping = false;
/// <summary>drawing Cache, if null, a redraw is done, cached or not</summary>
public Surface bmp;
public bool IsDirty = true;
if (parent == value)
return;
DataSourceChangeEventArgs e = new DataSourceChangeEventArgs (parent, value);
- lock (CurrentInterface.LayoutMutex) {
- parent = value;
- }
- onParentChanged (this, e);
-
+
+ parentRWLock.EnterWriteLock();
+ parent = value;
+ parentRWLock.ExitWriteLock();
+
+ onParentChanged (this, e);
}
}
[XmlIgnore]public ILayoutable LogicalParent {
/// Seek first logical tree upward if logicalParent is set, or seek graphic tree for
/// a not null dataSource that will be active for all descendants having dataSource=null
/// </summary>
- [XmlAttributeAttribute]//[DefaultValue(null)]
+ [XmlAttributeAttribute]
public virtual object DataSource {
set {
if (DataSource == value)
dataSource = value;
dse.NewDataSource = DataSource;
- //prevent setting null causing stack overflow in specific case
if (dse.NewDataSource == dse.OldDataSource)
return;
- lock (CurrentInterface.LayoutMutex) {
- OnDataSourceChanged (this, dse);
- }
+
+ OnDataSourceChanged (this, dse);
+
NotifyValueChanged ("DataSource", DataSource);
}
/// <summary> Loads the default values from XML attributes default </summary>
public void loadDefaultValues()
{
- #if DEBUG_LOAD
- Debug.WriteLine ("LoadDefValues for " + this.ToString ());
- #endif
+// #if DEBUG_LOAD
+// Debug.WriteLine ("LoadDefValues for " + this.ToString ());
+// #endif
Type thisType = this.GetType ();
#if DEBUG_UPDATE
Debug.WriteLine (string.Format("ClippingRegistration -> {0}", this.ToString ()));
#endif
- lock(CurrentInterface.LayoutMutex){
- IsQueueForRedraw = false;
- if (Parent == null)
- return;
+ parentRWLock.EnterReadLock ();
+ if (parent != null) {
Parent.RegisterClip (LastPaintedSlot);
Parent.RegisterClip (Slot);
}
+ parentRWLock.ExitReadLock ();
}
/// <summary>
/// Add clip rectangle to this.clipping and propagate up to root
using Cairo;
using System.Diagnostics;
using System.Reflection;
+using System.Threading;
namespace Crow
{
public class Group : GraphicObject
{
+ protected ReaderWriterLockSlim childrenRWLock = new ReaderWriterLockSlim();
+
#region CTOR
public Group () : base() {}
public Group(Interface iface) : base(iface){}
set { _multiSelect = value; }
}
public virtual void AddChild(GraphicObject g){
- lock (Children) {
- g.Parent = this;
- Children.Add (g);
- }
+ childrenRWLock.EnterWriteLock();
+
+ g.Parent = this;
+ Children.Add (g);
+
+ childrenRWLock.ExitWriteLock();
+
g.RegisteredLayoutings = LayoutingType.None;
g.LayoutChanged += OnChildLayoutChanges;
g.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren);
CurrentInterface.HoverWidget = null;
}
- lock (Children)
- Children.Remove(child);
+ childrenRWLock.EnterWriteLock ();
+
+ Children.Remove(child);
+
+ childrenRWLock.ExitWriteLock ();
if (child == largestChild && Width == Measure.Fit)
searchLargestChild ();
child.Dispose ();
}
public virtual void InsertChild (int idx, GraphicObject g) {
- lock (Children) {
- g.Parent = this;
- Children.Insert (idx, g);
- }
+ childrenRWLock.EnterWriteLock ();
+
+ g.Parent = this;
+ Children.Insert (idx, g);
+
+ childrenRWLock.ExitWriteLock ();
+
g.RegisteredLayoutings = LayoutingType.None;
g.LayoutChanged += OnChildLayoutChanges;
g.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren);
}
public virtual void ClearChildren()
{
- lock (Children) {
- while (Children.Count > 0) {
- GraphicObject g = Children [Children.Count - 1];
- g.LayoutChanged -= OnChildLayoutChanges;
- Children.RemoveAt (Children.Count - 1);
- g.Dispose ();
- }
+ childrenRWLock.EnterWriteLock ();
+
+ while (Children.Count > 0) {
+ GraphicObject g = Children [Children.Count - 1];
+ g.LayoutChanged -= OnChildLayoutChanges;
+ Children.RemoveAt (Children.Count - 1);
+ g.Dispose ();
}
+ childrenRWLock.ExitWriteLock ();
+
resetChildrenMaxSize ();
this.RegisterForLayouting (LayoutingType.Sizing);
{
if (Children.Contains(w))
{
- lock (Children) {
- Children.Remove (w);
- Children.Add (w);
- }
+ childrenRWLock.EnterWriteLock ();
+
+ Children.Remove (w);
+ Children.Add (w);
+
+ childrenRWLock.ExitWriteLock ();
}
}
public void putWidgetOnBottom(GraphicObject w)
{
if (Children.Contains(w))
{
- lock (Children) {
- Children.Remove (w);
- Children.Insert (0, w);
- }
+ childrenRWLock.EnterWriteLock ();
+
+ Children.Remove (w);
+ Children.Insert (0, w);
+
+ childrenRWLock.ExitWriteLock ();
}
}
public override void OnDataSourceChanged (object sender, DataSourceChangeEventArgs e)
{
base.OnDataSourceChanged (this, e);
- lock (Children) {
- foreach (GraphicObject g in children)
- if (g.localDataSourceIsNull & g.localLogicalParentIsNull)
- g.OnDataSourceChanged (g, e);
- }
+
+ childrenRWLock.EnterReadLock ();
+
+ foreach (GraphicObject g in children)
+ if (g.localDataSourceIsNull & g.localLogicalParentIsNull)
+ g.OnDataSourceChanged (g, e);
+
+ childrenRWLock.ExitReadLock ();
}
public override GraphicObject FindByName (string nameToFind)
{
if (Name == nameToFind)
return this;
GraphicObject tmp = null;
- lock (Children) {
- foreach (GraphicObject w in Children) {
- tmp = w.FindByName (nameToFind);
- if (tmp != null)
- break;
- }
+
+ childrenRWLock.EnterReadLock ();
+
+ foreach (GraphicObject w in Children) {
+ tmp = w.FindByName (nameToFind);
+ if (tmp != null)
+ break;
}
+
+ childrenRWLock.ExitReadLock ();
+
return tmp;
}
public override bool Contains (GraphicObject goToFind)
{
base.OnLayoutChanges (layoutType);
+ childrenRWLock.EnterReadLock ();
//position smaller objects in group when group size is fit
switch (layoutType) {
case LayoutingType.Width:
- foreach (GraphicObject c in Children){
+ foreach (GraphicObject c in Children) {
if (c.Width.Units == Unit.Percent)
c.RegisterForLayouting (LayoutingType.Width);
else
}
break;
}
+ childrenRWLock.ExitReadLock ();
}
protected override void onDraw (Context gr)
{
gr.Clip ();
}
- lock (Children) {
+ childrenRWLock.EnterReadLock ();
+
foreach (GraphicObject g in Children) {
g.Paint (ref gr);
}
- }
+
+ childrenRWLock.ExitReadLock ();
gr.Restore ();
}
protected override void UpdateCache (Context ctx)
gr.Clip ();
}
- lock (Children) {
- foreach (GraphicObject c in Children) {
- if (!c.Visible)
- continue;
- if (Clipping.Contains (c.Slot + ClientRectangle.Position) == RegionOverlap.Out)
- continue;
- c.Paint (ref gr);
- }
+ childrenRWLock.EnterReadLock ();
+
+ foreach (GraphicObject c in Children) {
+ if (!c.Visible)
+ continue;
+ if (Clipping.Contains (c.Slot + ClientRectangle.Position) == RegionOverlap.Out)
+ continue;
+ c.Paint (ref gr);
}
+ childrenRWLock.ExitReadLock ();
+
#if DEBUG_CLIP_RECTANGLE
Clipping.stroke (gr, Color.Amaranth.AdjustAlpha (0.8));
#endif
gr.Clip ();
}
- lock (Children) {
- TabItem[] tabItms = Children.Cast<TabItem> ().OrderBy (t => t.ViewIndex).ToArray ();
- for (int i = 0; i < tabItms.Length; i++) {
- if (tabItms [i] == Children [SelectedTab])
- continue;
- tabItms [i].Paint (ref gr);
- }
+ childrenRWLock.EnterReadLock ();
- if (SelectedTab < tabItms.Length && SelectedTab >= 0)
- Children [SelectedTab].Paint (ref gr);
+ TabItem[] tabItms = Children.Cast<TabItem> ().OrderBy (t => t.ViewIndex).ToArray ();
+ for (int i = 0; i < tabItms.Length; i++) {
+ if (tabItms [i] == Children [SelectedTab])
+ continue;
+ tabItms [i].Paint (ref gr);
}
+
+ if (SelectedTab < tabItms.Length && SelectedTab >= 0)
+ Children [SelectedTab].Paint (ref gr);
+
+ childrenRWLock.ExitReadLock ();
+
gr.Restore ();
}
else {
int dy = 0;
int largestChild = 0;
- lock (Children) {
- foreach (GraphicObject c in Children) {
- if (!c.Visible)
- continue;
- if (c.Height.Units == Unit.Percent &&
- c.RegisteredLayoutings.HasFlag (LayoutingType.Height))
- return -1;
- if (dy + c.Slot.Height > ClientRectangle.Height) {
- dy = 0;
- tmp += largestChild + Spacing;
- largestChild = c.Slot.Width;
- } else if (largestChild < c.Slot.Width)
- largestChild = c.Slot.Width;
-
- dy += c.Slot.Height + Spacing;
+
+ childrenRWLock.EnterReadLock();
+
+ foreach (GraphicObject c in Children) {
+ if (!c.Visible)
+ continue;
+ if (c.Height.Units == Unit.Percent &&
+ c.RegisteredLayoutings.HasFlag (LayoutingType.Height)) {
+ childrenRWLock.ExitReadLock();
+ return -1;
}
- if (dy == 0)
- tmp -= Spacing;
- return tmp + largestChild + 2 * Margin;
+ if (dy + c.Slot.Height > ClientRectangle.Height) {
+ dy = 0;
+ tmp += largestChild + Spacing;
+ largestChild = c.Slot.Width;
+ } else if (largestChild < c.Slot.Width)
+ largestChild = c.Slot.Width;
+
+ dy += c.Slot.Height + Spacing;
}
+
+ childrenRWLock.ExitReadLock ();
+
+ if (dy == 0)
+ tmp -= Spacing;
+ return tmp + largestChild + 2 * Margin;
}
} else if (Orientation == Orientation.Horizontal) {
Height = Measure.Stretched;
else {
int dx = 0;
int tallestChild = 0;
- lock (Children) {
- foreach (GraphicObject c in Children) {
- if (!c.Visible)
- continue;
- if (c.Width.Units == Unit.Percent &&
- c.RegisteredLayoutings.HasFlag (LayoutingType.Width))
- return -1;
- if (dx + c.Slot.Width > ClientRectangle.Width) {
- dx = 0;
- tmp += tallestChild + Spacing;
- tallestChild = c.Slot.Height;
- } else if (tallestChild < c.Slot.Height)
- tallestChild = c.Slot.Height;
- dx += c.Slot.Width + Spacing;
+ childrenRWLock.EnterReadLock();
+
+ foreach (GraphicObject c in Children) {
+ if (!c.Visible)
+ continue;
+ if (c.Width.Units == Unit.Percent &&
+ c.RegisteredLayoutings.HasFlag (LayoutingType.Width)) {
+ childrenRWLock.ExitReadLock();
+ return -1;
}
- if (dx == 0)
- tmp -= Spacing;
- return tmp + tallestChild + 2 * Margin;
+ if (dx + c.Slot.Width > ClientRectangle.Width) {
+ dx = 0;
+ tmp += tallestChild + Spacing;
+ tallestChild = c.Slot.Height;
+ } else if (tallestChild < c.Slot.Height)
+ tallestChild = c.Slot.Height;
+
+ dx += c.Slot.Width + Spacing;
}
+
+ childrenRWLock.ExitReadLock();
+
+ if (dx == 0)
+ tmp -= Spacing;
+ return tmp + tallestChild + 2 * Margin;
}
}
#if DEBUG_LOAD
loadingTime.Stop ();
Debug.WriteLine ("IML Instantiator creation '{2}' : {0} ticks, {1} ms",
- loadingTime.ElapsedTicks, loadingTime.ElapsedMilliseconds, imlPath);
+ loadingTime.ElapsedTicks, loadingTime.ElapsedMilliseconds, sourcePath);
#endif
}
}
public object RenderMutex = new object();
/// <summary>Global lock of the update cycle</summary>
public object UpdateMutex = new object();
+ /// <summary>Global lock of the clipping queue</summary>
+ public object ClippingMutex = new object();
//TODO:share resource instances
/// <summary>
/// Store loaded resources instances shared among controls to reduce memory footprint
/// <summary>Store discarded lqi between two updates</summary>
public Queue<LayoutingQueueItem> DiscardQueue;
/// <summary>Main drawing queue, holding layouted controls</summary>
- public Queue<GraphicObject> DrawingQueue = new Queue<GraphicObject>();
+ public Queue<GraphicObject> ClippingQueue = new Queue<GraphicObject>();
public string Clipboard;//TODO:use object instead for complex copy paste
/// <summary>each IML and fragments (such as inline Templates) are compiled as a Dynamic Method stored here
/// on the first instance creation of a IML item.
#if DEBUG_UPDATE
Debug.WriteLine (string.Format("\tEnqueueForRepaint -> {0}", g?.ToString ()));
#endif
- lock (DrawingQueue) {
- if (g.IsQueueForRedraw)
+ lock (ClippingMutex) {
+ if (g.IsQueueForClipping)
return;
- DrawingQueue.Enqueue (g);
- g.IsQueueForRedraw = true;
+ ClippingQueue.Enqueue (g);
+ g.IsQueueForClipping = true;
}
}
/// <summary>Main Update loop, executed in this interface thread, protected by the UpdateMutex
clippingMeasure.StartCycle();
#endif
GraphicObject g = null;
- while (DrawingQueue.Count > 0) {
- lock (DrawingQueue)
- g = DrawingQueue.Dequeue ();
+ while (ClippingQueue.Count > 0) {
+ lock (ClippingMutex) {
+ g = ClippingQueue.Dequeue ();
+ g.IsQueueForClipping = false;
+ }
g.ClippingRegistration ();
}
public void ProcessLayouting()
{
- if (Layoutable.Parent == null) {//TODO:improve this
+ GraphicObject go = Layoutable as GraphicObject;
+ if (go == null) {
+ Debug.WriteLine ("ERROR: processLayouting on something else than a graphic object: " + this.ToString ());
+ return;
+ }
+
+ go.parentRWLock.EnterReadLock ();
+
+ if (go.Parent == null) {//TODO:improve this
//cancel layouting for object without parent, maybe some were in queue when
//removed from a listbox
#if DEBUG_UPDATE || DEBUG_LAYOUTING
Debug.WriteLine ("ERROR: processLayouting, no parent for: " + this.ToString ());
#endif
+ go.parentRWLock.ExitReadLock ();
return;
}
#if DEBUG_LAYOUTING
}
LQITime.Stop();
#endif
+ go.parentRWLock.ExitReadLock ();
}
public static implicit operator GraphicObject(LayoutingQueueItem queueItem)