Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Core / CSharp / System / Windows / Input / Stylus / StylusPlugInCollection.cs / 1 / StylusPlugInCollection.cs
//------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//-----------------------------------------------------------------------
using System;
using System.Windows;
using System.Collections;
using System.Collections.ObjectModel;
using System.Windows.Media;
using System.Windows.Threading;
using System.Windows.Interop;
using System.Security;
using System.Security.Permissions;
using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID;
namespace System.Windows.Input.StylusPlugIns
{
///
/// Collection of StylusPlugIn objects
///
///
/// The collection order is based on the order that StylusPlugIn objects are
/// added to the collection via the IList interfaces. The order of the StylusPlugIn
/// objects in the collection is modifiable.
/// Some of the methods are designed to be called from both the App thread and the Pen thread,
/// but some of them are supposed to be called from one thread only. Please look at the
/// comments of each method for such an information.
///
public sealed class StylusPlugInCollection : Collection
{
#region Protected APIs
///
/// Insert a StylusPlugIn in the collection at a specific index.
/// This method should be called from the application context only
///
/// index at which to insert the StylusPlugIn object
/// StylusPlugIn object to insert, downcast to an object
protected override void InsertItem(int index, StylusPlugIn plugIn)
{
// Verify it's called from the app dispatcher
_element.VerifyAccess();
// Validate the input parameter
if (null == plugIn)
{
throw new ArgumentNullException("plugIn", SR.Get(SRID.Stylus_PlugInIsNull));
}
if (IndexOf(plugIn) != -1)
{
throw new ArgumentException(SR.Get(SRID.Stylus_PlugInIsDuplicated), "plugIn");
}
// Disable processing of the queue during blocking operations to prevent unrelated reentrancy
// which a call to Lock() can cause.
using (_element.Dispatcher.DisableProcessing())
{
if (IsActiveForInput)
{
// If we are currently active for input then we have a _penContexts that we must lock!
lock(PenContextsSyncRoot)
{
System.Diagnostics.Debug.Assert(this.Count > 0); // If active must have more than one plugin already
base.InsertItem(index, plugIn);
plugIn.Added(this);
}
}
else
{
EnsureEventsHooked(); // Hook up events to track changes to the plugin's element
base.InsertItem(index, plugIn);
try
{
plugIn.Added(this); // Notify plugin that it has been added to collection
}
finally
{
UpdatePenContextsState(); // Add to PenContexts if element is in proper state (can fire isactiveforinput).
}
}
}
}
///
/// Remove all the StylusPlugIn objects from the collection.
/// This method should be called from the application context only.
///
protected override void ClearItems()
{
// Verify it's called from the app dispatcher
_element.VerifyAccess();
if (this.Count != 0)
{
// Disable processing of the queue during blocking operations to prevent unrelated reentrancy
// which a call to Lock() can cause.
using (_element.Dispatcher.DisableProcessing())
{
if (IsActiveForInput)
{
// If we are currently active for input then we have a _penContexts that we must lock!
lock(PenContextsSyncRoot)
{
while (this.Count > 0)
{
RemoveItem(0); // Does work to fire event and remove from collection and pencontexts
}
}
}
else
{
while (this.Count > 0)
{
RemoveItem(0); // Does work to fire event and remove from collection.
}
}
}
}
}
///
/// Remove the StylusPlugIn in the collection at the specified index.
/// This method should be called from the application context only.
///
///
protected override void RemoveItem(int index)
{
// Verify it's called from the app dispatcher
_element.VerifyAccess();
// Disable processing of the queue during blocking operations to prevent unrelated reentrancy
// which a call to Lock() can cause.
using (_element.Dispatcher.DisableProcessing())
{
if (IsActiveForInput)
{
// If we are currently active for input then we have a _penContexts that we must lock!
lock(PenContextsSyncRoot)
{
StylusPlugIn removedItem = base[index];
base.RemoveItem(index);
try
{
EnsureEventsAndPenContextsUnhooked(); // Clean up events and remove from pencontexts
}
finally
{
removedItem.Removed(); // Notify plugin it has been removed
}
}
}
else
{
StylusPlugIn removedItem = base[index];
base.RemoveItem(index);
try
{
EnsureEventsAndPenContextsUnhooked(); // Clean up events and remove from pencontexts
}
finally
{
removedItem.Removed(); // Notify plugin it has been removed
}
}
}
}
///
/// Indexer to retrieve/set a StylusPlugIn at a given index in the collection
/// Accessible from both the real time context and application context.
///
protected override void SetItem(int index, StylusPlugIn plugIn)
{
// Verify it's called from the app dispatcher
_element.VerifyAccess();
if (null == plugIn)
{
throw new ArgumentNullException("plugIn", SR.Get(SRID.Stylus_PlugInIsNull));
}
if (IndexOf(plugIn) != -1)
{
throw new ArgumentException(SR.Get(SRID.Stylus_PlugInIsDuplicated), "plugIn");
}
// Disable processing of the queue during blocking operations to prevent unrelated reentrancy
// which a call to Lock() can cause.
using (_element.Dispatcher.DisableProcessing())
{
if (IsActiveForInput)
{
// If we are currently active for input then we have a _penContexts that we must lock!
lock(PenContextsSyncRoot)
{
StylusPlugIn originalPlugIn = base[index];
base.SetItem(index, plugIn);
try
{
originalPlugIn.Removed();
}
finally
{
plugIn.Added(this);
}
}
}
else
{
StylusPlugIn originalPlugIn = base[index];
base.SetItem(index, plugIn);
try
{
originalPlugIn.Removed();
}
finally
{
plugIn.Added(this);
}
}
}
}
#endregion
#region Internal APIs
///
/// Constructor
///
///
internal StylusPlugInCollection(UIElement element)
{
_element = element;
_isEnabledChangedEventHandler = new DependencyPropertyChangedEventHandler(OnIsEnabledChanged);
_isVisibleChangedEventHandler = new DependencyPropertyChangedEventHandler(OnIsVisibleChanged);
_isHitTestVisibleChangedEventHandler = new DependencyPropertyChangedEventHandler(OnIsHitTestVisibleChanged);
_sourceChangedEventHandler = new SourceChangedEventHandler(OnSourceChanged);
_layoutChangedEventHandler = new EventHandler(OnLayoutUpdated);
}
///
/// Get the UIElement
/// This method is called from the real-time context.
///
internal UIElement Element
{
get
{
return _element;
}
}
///
/// Update the rectangular bound of the element
/// This method is called from the application context.
///
internal void UpdateRect()
{
// The RenderSize is only valid if IsArrangeValid is true.
if (_element.IsArrangeValid && _element.IsEnabled && _element.IsVisible && _element.IsHitTestVisible)
{
_rc = new Rect(new Point(), _element.RenderSize);// _element.GetContentBoundingBox();
Visual root = VisualTreeHelper.GetContainingVisual2D(InputElement.GetRootVisual(_element));
try
{
_viewToElement = root.TransformToDescendant(_element);
}
catch(System.InvalidOperationException)
{
// This gets hit if the transform is not invertable. In that case
// we will just not allow this plugin to be hit.
_rc = new Rect(); // empty rect so we don't hittest it.
_viewToElement = Transform.Identity;
}
}
else
{
_rc = new Rect(); // empty rect so we don't hittest it.
}
if (_viewToElement == null)
{
_viewToElement = Transform.Identity;
}
}
///
/// Check whether a point hits the element
/// This method is called from the real-time context.
///
/// a point to check
/// true if the point is within the bound of the element; false otherwise
internal bool IsHit(Point pt)
{
Point ptElement = pt;
_viewToElement.TryTransform(ptElement, out ptElement);
return _rc.Contains(ptElement);
}
///
/// Get the transform matrix from the root visual to the current UIElement
/// This method is called from the real-time context.
///
internal GeneralTransform ViewToElement
{
get
{
return _viewToElement;
}
}
///
/// Get the current rect for the Element that the StylusPlugInCollection is attached to.
/// May be empty rect if plug in is not in tree.
///
internal Rect Rect
{
get
{
return _rc;
}
}
///
/// Get the current rect for the Element that the StylusPlugInCollection is attached to.
/// May be empty rect if plug in is not in tree.
///
///
/// Critical - Accesses SecurityCritical data _penContexts.
/// TreatAsSafe - Just returns if _pencontexts is null. No data goes in or out. Knowing
/// the fact that you can recieve real time input is something that is safe
/// to know and we want to expose.
///
internal bool IsActiveForInput
{
[SecurityCritical, SecurityTreatAsSafe]
get
{
return _penContexts != null;
}
}
///
/// Critical - Accesses SecurityCritical data _penContexts.
/// TreatAsSafe - The [....] object on the _penContexts object is not considered security
/// critical data. It is already internally exposed directly on the
/// PenContexts object.
///
internal object PenContextsSyncRoot
{
[SecurityCritical, SecurityTreatAsSafe]
get
{
return _penContexts != null ? _penContexts.SyncRoot : null;
}
}
///
/// Fire the Enter notification.
/// This method is called from pen threads and app thread.
///
internal void FireEnterLeave(bool isEnter, RawStylusInput rawStylusInput, bool confirmed)
{
if (IsActiveForInput)
{
// If we are currently active for input then we have a _penContexts that we must lock!
lock(PenContextsSyncRoot)
{
for (int i = 0; i < this.Count; i++)
{
base[i].StylusEnterLeave(isEnter, rawStylusInput, confirmed);
}
}
}
else
{
for (int i = 0; i < this.Count; i++)
{
base[i].StylusEnterLeave(isEnter, rawStylusInput, confirmed);
}
}
}
///
/// Fire RawStylusInputEvent for all the StylusPlugIns
/// This method is called from the real-time context (pen thread) only
///
///
internal void FireRawStylusInput(RawStylusInput args)
{
try
{
if (IsActiveForInput)
{
// If we are currently active for input then we have a _penContexts that we must lock!
lock(PenContextsSyncRoot)
{
for (int i = 0; i < this.Count; i++)
{
StylusPlugIn plugIn = base[i];
// set current plugin so any callback data gets an owner.
args.CurrentNotifyPlugIn = plugIn;
plugIn.RawStylusInput(args);
}
}
}
else
{
for (int i = 0; i < this.Count; i++)
{
StylusPlugIn plugIn = base[i];
// set current plugin so any callback data gets an owner.
args.CurrentNotifyPlugIn = plugIn;
plugIn.RawStylusInput(args);
}
}
}
finally
{
args.CurrentNotifyPlugIn = null;
}
}
///
/// Critical: Accesses critical member _penContexts.
///
internal PenContexts PenContexts
{
[SecurityCritical]
get
{
return _penContexts;
}
}
#endregion
#region Private APIs
///
/// Add this StylusPlugInCollection to the StylusPlugInCollectionList when it the first
/// element is added.
///
///
/// Critical - Presentation source access
/// TreatAsSafe: - PresentationSource makes a SecurityDemand
/// - no data handed out or accepted
/// - called by Add and Insert
///
[SecurityCritical,SecurityTreatAsSafe]
private void EnsureEventsHooked()
{
if (this.Count == 0)
{
// Grab current element info
UpdateRect();
// Now hook up events to track on this element.
_element.IsEnabledChanged += _isEnabledChangedEventHandler;
_element.IsVisibleChanged += _isVisibleChangedEventHandler;
_element.IsHitTestVisibleChanged += _isHitTestVisibleChangedEventHandler;
PresentationSource.AddSourceChangedHandler(_element, _sourceChangedEventHandler); // has a security linkdemand
_element.LayoutUpdated += _layoutChangedEventHandler;
if (_element.RenderTransform != null &&
!_element.RenderTransform.IsFrozen)
{
if (_renderTransformChangedEventHandler == null)
{
_renderTransformChangedEventHandler = new EventHandler(OnRenderTransformChanged);
_element.RenderTransform.Changed += _renderTransformChangedEventHandler;
}
}
}
}
///
/// Remove this StylusPlugInCollection from the StylusPlugInCollectionList when it the last
/// element is removed for this collection.
///
private void EnsureEventsAndPenContextsUnhooked()
{
if (this.Count == 0)
{
// Unhook events.
_element.IsEnabledChanged -= _isEnabledChangedEventHandler;
_element.IsVisibleChanged -= _isVisibleChangedEventHandler;
_element.IsHitTestVisibleChanged -= _isHitTestVisibleChangedEventHandler;
if (_renderTransformChangedEventHandler != null)
{
_element.RenderTransform.Changed -= _renderTransformChangedEventHandler;
}
PresentationSource.RemoveSourceChangedHandler(_element, _sourceChangedEventHandler);
_element.LayoutUpdated -= _layoutChangedEventHandler;
// Disable processing of the queue during blocking operations to prevent unrelated reentrancy
// which a call to Lock() can cause.
using (_element.Dispatcher.DisableProcessing())
{
// Make sure we are unhooked from PenContexts if we don't have any plugins.
UnhookPenContexts();
}
}
}
private void OnIsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
System.Diagnostics.Debug.Assert(_element.IsEnabled == (bool)e.NewValue);
UpdatePenContextsState();
}
private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
System.Diagnostics.Debug.Assert(_element.IsVisible == (bool)e.NewValue);
UpdatePenContextsState();
}
private void OnIsHitTestVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
System.Diagnostics.Debug.Assert(_element.IsHitTestVisible == (bool)e.NewValue);
UpdatePenContextsState();
}
private void OnRenderTransformChanged(object sender, EventArgs e)
{
OnLayoutUpdated(sender, e);
}
private void OnSourceChanged(object sender, SourceChangedEventArgs e)
{
// This means that the element has been added or remvoed from its source.
UpdatePenContextsState();
}
private void OnLayoutUpdated(object sender, EventArgs e)
{
// Make sure our rect and transform is up to date on layout changes.
// NOTE: We need to make sure we do this under a lock if we are active for input since we don't
// want the PenContexts code to get a mismatched set of state for this element.
if (IsActiveForInput)
{
// Disable processing of the queue during blocking operations to prevent unrelated reentrancy
// which a call to Lock() can cause.
using (_element.Dispatcher.DisableProcessing())
{
// If we are currently active for input then we have a _penContexts that we must lock!
lock(PenContextsSyncRoot)
{
UpdateRect();
}
}
}
else
{
UpdateRect();
}
if (_lastRenderTransform != _element.RenderTransform)
{
if (_renderTransformChangedEventHandler != null)
{
_lastRenderTransform.Changed -= _renderTransformChangedEventHandler;
_renderTransformChangedEventHandler = null;
}
_lastRenderTransform = _element.RenderTransform;
}
if (_lastRenderTransform != null)
{
if (_lastRenderTransform.IsFrozen)
{
if (_renderTransformChangedEventHandler != null)
{
_renderTransformChangedEventHandler = null;
}
}
else
{
if (_renderTransformChangedEventHandler == null)
{
_renderTransformChangedEventHandler = new EventHandler(OnRenderTransformChanged);
_lastRenderTransform.Changed += _renderTransformChangedEventHandler;
}
}
}
}
// On app ui dispatcher
///
/// Critical - Presentation source access
/// Calls SecurityCritical routines PresentationSource.CriticalFromVisual and
/// HwndSource.CriticalHandle.
/// TreatAsSafe:
/// - no data handed out or accepted
///
[SecurityCritical,SecurityTreatAsSafe]
private void UpdatePenContextsState()
{
bool unhookPenContexts = true;
// Disable processing of the queue during blocking operations to prevent unrelated reentrancy
// which a call to Lock() can cause.
using (_element.Dispatcher.DisableProcessing())
{
// See if we should be enabled
if (_element.IsVisible && _element.IsEnabled && _element.IsHitTestVisible)
{
PresentationSource presentationSource = PresentationSource.CriticalFromVisual(_element as Visual);
if (presentationSource != null)
{
unhookPenContexts = false;
// Are we currently hooked up? If not then hook up.
if (_penContexts == null)
{
InputManager inputManager = (InputManager)_element.Dispatcher.InputManager;
PenContexts penContexts = inputManager.StylusLogic.GetPenContextsFromHwnd(presentationSource);
// _penContexts must be non null or don't do anything.
if (penContexts != null)
{
_penContexts = penContexts;
lock(penContexts.SyncRoot)
{
penContexts.AddStylusPlugInCollection(this);
foreach (StylusPlugIn spi in this)
{
spi.InvalidateIsActiveForInput(); // Uses _penContexts being set to determine active state.
}
// NTRAID:WINDOWSOS#1677277-2006/06/05-WAYNEZEN,
// Normally the Rect will be updated when we receive the LayoutUpdate.
// However there could be a race condition which the LayoutUpdate gets received
// before the properties like IsVisible being set.
// So we should always force to call OnLayoutUpdated whenever the input is active.
OnLayoutUpdated(this, EventArgs.Empty);
}
}
}
}
}
if (unhookPenContexts)
{
UnhookPenContexts();
}
}
}
///
/// Critical - _penContexts access
/// TreatAsSafe:
/// - no data handed out or accepted
///
[SecurityCritical,SecurityTreatAsSafe]
void UnhookPenContexts()
{
// Are we currently unhooked? If not then unhook.
if (_penContexts != null)
{
lock(_penContexts.SyncRoot)
{
_penContexts.RemoveStylusPlugInCollection(this);
// Can't recieve any more input now!
_penContexts = null;
// Notify after input is disabled to the PlugIns.
foreach (StylusPlugIn spi in this)
{
spi.InvalidateIsActiveForInput();
}
}
}
}
#endregion
#region Fields
private UIElement _element;
private Rect _rc; // In window root measured units
private GeneralTransform _viewToElement;
private Transform _lastRenderTransform;
// Note that this is only set when the Element is in a state to receive input (visible,enabled,in tree).
///
/// Critical to prevent accidental spread to transparent code
///
[SecurityCritical]
private PenContexts _penContexts;
private DependencyPropertyChangedEventHandler _isEnabledChangedEventHandler;
private DependencyPropertyChangedEventHandler _isVisibleChangedEventHandler;
private DependencyPropertyChangedEventHandler _isHitTestVisibleChangedEventHandler;
private EventHandler _renderTransformChangedEventHandler;
private SourceChangedEventHandler _sourceChangedEventHandler;
private EventHandler _layoutChangedEventHandler;
#endregion
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//-----------------------------------------------------------------------
using System;
using System.Windows;
using System.Collections;
using System.Collections.ObjectModel;
using System.Windows.Media;
using System.Windows.Threading;
using System.Windows.Interop;
using System.Security;
using System.Security.Permissions;
using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID;
namespace System.Windows.Input.StylusPlugIns
{
///
/// Collection of StylusPlugIn objects
///
///
/// The collection order is based on the order that StylusPlugIn objects are
/// added to the collection via the IList interfaces. The order of the StylusPlugIn
/// objects in the collection is modifiable.
/// Some of the methods are designed to be called from both the App thread and the Pen thread,
/// but some of them are supposed to be called from one thread only. Please look at the
/// comments of each method for such an information.
///
public sealed class StylusPlugInCollection : Collection
{
#region Protected APIs
///
/// Insert a StylusPlugIn in the collection at a specific index.
/// This method should be called from the application context only
///
/// index at which to insert the StylusPlugIn object
/// StylusPlugIn object to insert, downcast to an object
protected override void InsertItem(int index, StylusPlugIn plugIn)
{
// Verify it's called from the app dispatcher
_element.VerifyAccess();
// Validate the input parameter
if (null == plugIn)
{
throw new ArgumentNullException("plugIn", SR.Get(SRID.Stylus_PlugInIsNull));
}
if (IndexOf(plugIn) != -1)
{
throw new ArgumentException(SR.Get(SRID.Stylus_PlugInIsDuplicated), "plugIn");
}
// Disable processing of the queue during blocking operations to prevent unrelated reentrancy
// which a call to Lock() can cause.
using (_element.Dispatcher.DisableProcessing())
{
if (IsActiveForInput)
{
// If we are currently active for input then we have a _penContexts that we must lock!
lock(PenContextsSyncRoot)
{
System.Diagnostics.Debug.Assert(this.Count > 0); // If active must have more than one plugin already
base.InsertItem(index, plugIn);
plugIn.Added(this);
}
}
else
{
EnsureEventsHooked(); // Hook up events to track changes to the plugin's element
base.InsertItem(index, plugIn);
try
{
plugIn.Added(this); // Notify plugin that it has been added to collection
}
finally
{
UpdatePenContextsState(); // Add to PenContexts if element is in proper state (can fire isactiveforinput).
}
}
}
}
///
/// Remove all the StylusPlugIn objects from the collection.
/// This method should be called from the application context only.
///
protected override void ClearItems()
{
// Verify it's called from the app dispatcher
_element.VerifyAccess();
if (this.Count != 0)
{
// Disable processing of the queue during blocking operations to prevent unrelated reentrancy
// which a call to Lock() can cause.
using (_element.Dispatcher.DisableProcessing())
{
if (IsActiveForInput)
{
// If we are currently active for input then we have a _penContexts that we must lock!
lock(PenContextsSyncRoot)
{
while (this.Count > 0)
{
RemoveItem(0); // Does work to fire event and remove from collection and pencontexts
}
}
}
else
{
while (this.Count > 0)
{
RemoveItem(0); // Does work to fire event and remove from collection.
}
}
}
}
}
///
/// Remove the StylusPlugIn in the collection at the specified index.
/// This method should be called from the application context only.
///
///
protected override void RemoveItem(int index)
{
// Verify it's called from the app dispatcher
_element.VerifyAccess();
// Disable processing of the queue during blocking operations to prevent unrelated reentrancy
// which a call to Lock() can cause.
using (_element.Dispatcher.DisableProcessing())
{
if (IsActiveForInput)
{
// If we are currently active for input then we have a _penContexts that we must lock!
lock(PenContextsSyncRoot)
{
StylusPlugIn removedItem = base[index];
base.RemoveItem(index);
try
{
EnsureEventsAndPenContextsUnhooked(); // Clean up events and remove from pencontexts
}
finally
{
removedItem.Removed(); // Notify plugin it has been removed
}
}
}
else
{
StylusPlugIn removedItem = base[index];
base.RemoveItem(index);
try
{
EnsureEventsAndPenContextsUnhooked(); // Clean up events and remove from pencontexts
}
finally
{
removedItem.Removed(); // Notify plugin it has been removed
}
}
}
}
///
/// Indexer to retrieve/set a StylusPlugIn at a given index in the collection
/// Accessible from both the real time context and application context.
///
protected override void SetItem(int index, StylusPlugIn plugIn)
{
// Verify it's called from the app dispatcher
_element.VerifyAccess();
if (null == plugIn)
{
throw new ArgumentNullException("plugIn", SR.Get(SRID.Stylus_PlugInIsNull));
}
if (IndexOf(plugIn) != -1)
{
throw new ArgumentException(SR.Get(SRID.Stylus_PlugInIsDuplicated), "plugIn");
}
// Disable processing of the queue during blocking operations to prevent unrelated reentrancy
// which a call to Lock() can cause.
using (_element.Dispatcher.DisableProcessing())
{
if (IsActiveForInput)
{
// If we are currently active for input then we have a _penContexts that we must lock!
lock(PenContextsSyncRoot)
{
StylusPlugIn originalPlugIn = base[index];
base.SetItem(index, plugIn);
try
{
originalPlugIn.Removed();
}
finally
{
plugIn.Added(this);
}
}
}
else
{
StylusPlugIn originalPlugIn = base[index];
base.SetItem(index, plugIn);
try
{
originalPlugIn.Removed();
}
finally
{
plugIn.Added(this);
}
}
}
}
#endregion
#region Internal APIs
///
/// Constructor
///
///
internal StylusPlugInCollection(UIElement element)
{
_element = element;
_isEnabledChangedEventHandler = new DependencyPropertyChangedEventHandler(OnIsEnabledChanged);
_isVisibleChangedEventHandler = new DependencyPropertyChangedEventHandler(OnIsVisibleChanged);
_isHitTestVisibleChangedEventHandler = new DependencyPropertyChangedEventHandler(OnIsHitTestVisibleChanged);
_sourceChangedEventHandler = new SourceChangedEventHandler(OnSourceChanged);
_layoutChangedEventHandler = new EventHandler(OnLayoutUpdated);
}
///
/// Get the UIElement
/// This method is called from the real-time context.
///
internal UIElement Element
{
get
{
return _element;
}
}
///
/// Update the rectangular bound of the element
/// This method is called from the application context.
///
internal void UpdateRect()
{
// The RenderSize is only valid if IsArrangeValid is true.
if (_element.IsArrangeValid && _element.IsEnabled && _element.IsVisible && _element.IsHitTestVisible)
{
_rc = new Rect(new Point(), _element.RenderSize);// _element.GetContentBoundingBox();
Visual root = VisualTreeHelper.GetContainingVisual2D(InputElement.GetRootVisual(_element));
try
{
_viewToElement = root.TransformToDescendant(_element);
}
catch(System.InvalidOperationException)
{
// This gets hit if the transform is not invertable. In that case
// we will just not allow this plugin to be hit.
_rc = new Rect(); // empty rect so we don't hittest it.
_viewToElement = Transform.Identity;
}
}
else
{
_rc = new Rect(); // empty rect so we don't hittest it.
}
if (_viewToElement == null)
{
_viewToElement = Transform.Identity;
}
}
///
/// Check whether a point hits the element
/// This method is called from the real-time context.
///
/// a point to check
/// true if the point is within the bound of the element; false otherwise
internal bool IsHit(Point pt)
{
Point ptElement = pt;
_viewToElement.TryTransform(ptElement, out ptElement);
return _rc.Contains(ptElement);
}
///
/// Get the transform matrix from the root visual to the current UIElement
/// This method is called from the real-time context.
///
internal GeneralTransform ViewToElement
{
get
{
return _viewToElement;
}
}
///
/// Get the current rect for the Element that the StylusPlugInCollection is attached to.
/// May be empty rect if plug in is not in tree.
///
internal Rect Rect
{
get
{
return _rc;
}
}
///
/// Get the current rect for the Element that the StylusPlugInCollection is attached to.
/// May be empty rect if plug in is not in tree.
///
///
/// Critical - Accesses SecurityCritical data _penContexts.
/// TreatAsSafe - Just returns if _pencontexts is null. No data goes in or out. Knowing
/// the fact that you can recieve real time input is something that is safe
/// to know and we want to expose.
///
internal bool IsActiveForInput
{
[SecurityCritical, SecurityTreatAsSafe]
get
{
return _penContexts != null;
}
}
///
/// Critical - Accesses SecurityCritical data _penContexts.
/// TreatAsSafe - The [....] object on the _penContexts object is not considered security
/// critical data. It is already internally exposed directly on the
/// PenContexts object.
///
internal object PenContextsSyncRoot
{
[SecurityCritical, SecurityTreatAsSafe]
get
{
return _penContexts != null ? _penContexts.SyncRoot : null;
}
}
///
/// Fire the Enter notification.
/// This method is called from pen threads and app thread.
///
internal void FireEnterLeave(bool isEnter, RawStylusInput rawStylusInput, bool confirmed)
{
if (IsActiveForInput)
{
// If we are currently active for input then we have a _penContexts that we must lock!
lock(PenContextsSyncRoot)
{
for (int i = 0; i < this.Count; i++)
{
base[i].StylusEnterLeave(isEnter, rawStylusInput, confirmed);
}
}
}
else
{
for (int i = 0; i < this.Count; i++)
{
base[i].StylusEnterLeave(isEnter, rawStylusInput, confirmed);
}
}
}
///
/// Fire RawStylusInputEvent for all the StylusPlugIns
/// This method is called from the real-time context (pen thread) only
///
///
internal void FireRawStylusInput(RawStylusInput args)
{
try
{
if (IsActiveForInput)
{
// If we are currently active for input then we have a _penContexts that we must lock!
lock(PenContextsSyncRoot)
{
for (int i = 0; i < this.Count; i++)
{
StylusPlugIn plugIn = base[i];
// set current plugin so any callback data gets an owner.
args.CurrentNotifyPlugIn = plugIn;
plugIn.RawStylusInput(args);
}
}
}
else
{
for (int i = 0; i < this.Count; i++)
{
StylusPlugIn plugIn = base[i];
// set current plugin so any callback data gets an owner.
args.CurrentNotifyPlugIn = plugIn;
plugIn.RawStylusInput(args);
}
}
}
finally
{
args.CurrentNotifyPlugIn = null;
}
}
///
/// Critical: Accesses critical member _penContexts.
///
internal PenContexts PenContexts
{
[SecurityCritical]
get
{
return _penContexts;
}
}
#endregion
#region Private APIs
///
/// Add this StylusPlugInCollection to the StylusPlugInCollectionList when it the first
/// element is added.
///
///
/// Critical - Presentation source access
/// TreatAsSafe: - PresentationSource makes a SecurityDemand
/// - no data handed out or accepted
/// - called by Add and Insert
///
[SecurityCritical,SecurityTreatAsSafe]
private void EnsureEventsHooked()
{
if (this.Count == 0)
{
// Grab current element info
UpdateRect();
// Now hook up events to track on this element.
_element.IsEnabledChanged += _isEnabledChangedEventHandler;
_element.IsVisibleChanged += _isVisibleChangedEventHandler;
_element.IsHitTestVisibleChanged += _isHitTestVisibleChangedEventHandler;
PresentationSource.AddSourceChangedHandler(_element, _sourceChangedEventHandler); // has a security linkdemand
_element.LayoutUpdated += _layoutChangedEventHandler;
if (_element.RenderTransform != null &&
!_element.RenderTransform.IsFrozen)
{
if (_renderTransformChangedEventHandler == null)
{
_renderTransformChangedEventHandler = new EventHandler(OnRenderTransformChanged);
_element.RenderTransform.Changed += _renderTransformChangedEventHandler;
}
}
}
}
///
/// Remove this StylusPlugInCollection from the StylusPlugInCollectionList when it the last
/// element is removed for this collection.
///
private void EnsureEventsAndPenContextsUnhooked()
{
if (this.Count == 0)
{
// Unhook events.
_element.IsEnabledChanged -= _isEnabledChangedEventHandler;
_element.IsVisibleChanged -= _isVisibleChangedEventHandler;
_element.IsHitTestVisibleChanged -= _isHitTestVisibleChangedEventHandler;
if (_renderTransformChangedEventHandler != null)
{
_element.RenderTransform.Changed -= _renderTransformChangedEventHandler;
}
PresentationSource.RemoveSourceChangedHandler(_element, _sourceChangedEventHandler);
_element.LayoutUpdated -= _layoutChangedEventHandler;
// Disable processing of the queue during blocking operations to prevent unrelated reentrancy
// which a call to Lock() can cause.
using (_element.Dispatcher.DisableProcessing())
{
// Make sure we are unhooked from PenContexts if we don't have any plugins.
UnhookPenContexts();
}
}
}
private void OnIsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
System.Diagnostics.Debug.Assert(_element.IsEnabled == (bool)e.NewValue);
UpdatePenContextsState();
}
private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
System.Diagnostics.Debug.Assert(_element.IsVisible == (bool)e.NewValue);
UpdatePenContextsState();
}
private void OnIsHitTestVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
System.Diagnostics.Debug.Assert(_element.IsHitTestVisible == (bool)e.NewValue);
UpdatePenContextsState();
}
private void OnRenderTransformChanged(object sender, EventArgs e)
{
OnLayoutUpdated(sender, e);
}
private void OnSourceChanged(object sender, SourceChangedEventArgs e)
{
// This means that the element has been added or remvoed from its source.
UpdatePenContextsState();
}
private void OnLayoutUpdated(object sender, EventArgs e)
{
// Make sure our rect and transform is up to date on layout changes.
// NOTE: We need to make sure we do this under a lock if we are active for input since we don't
// want the PenContexts code to get a mismatched set of state for this element.
if (IsActiveForInput)
{
// Disable processing of the queue during blocking operations to prevent unrelated reentrancy
// which a call to Lock() can cause.
using (_element.Dispatcher.DisableProcessing())
{
// If we are currently active for input then we have a _penContexts that we must lock!
lock(PenContextsSyncRoot)
{
UpdateRect();
}
}
}
else
{
UpdateRect();
}
if (_lastRenderTransform != _element.RenderTransform)
{
if (_renderTransformChangedEventHandler != null)
{
_lastRenderTransform.Changed -= _renderTransformChangedEventHandler;
_renderTransformChangedEventHandler = null;
}
_lastRenderTransform = _element.RenderTransform;
}
if (_lastRenderTransform != null)
{
if (_lastRenderTransform.IsFrozen)
{
if (_renderTransformChangedEventHandler != null)
{
_renderTransformChangedEventHandler = null;
}
}
else
{
if (_renderTransformChangedEventHandler == null)
{
_renderTransformChangedEventHandler = new EventHandler(OnRenderTransformChanged);
_lastRenderTransform.Changed += _renderTransformChangedEventHandler;
}
}
}
}
// On app ui dispatcher
///
/// Critical - Presentation source access
/// Calls SecurityCritical routines PresentationSource.CriticalFromVisual and
/// HwndSource.CriticalHandle.
/// TreatAsSafe:
/// - no data handed out or accepted
///
[SecurityCritical,SecurityTreatAsSafe]
private void UpdatePenContextsState()
{
bool unhookPenContexts = true;
// Disable processing of the queue during blocking operations to prevent unrelated reentrancy
// which a call to Lock() can cause.
using (_element.Dispatcher.DisableProcessing())
{
// See if we should be enabled
if (_element.IsVisible && _element.IsEnabled && _element.IsHitTestVisible)
{
PresentationSource presentationSource = PresentationSource.CriticalFromVisual(_element as Visual);
if (presentationSource != null)
{
unhookPenContexts = false;
// Are we currently hooked up? If not then hook up.
if (_penContexts == null)
{
InputManager inputManager = (InputManager)_element.Dispatcher.InputManager;
PenContexts penContexts = inputManager.StylusLogic.GetPenContextsFromHwnd(presentationSource);
// _penContexts must be non null or don't do anything.
if (penContexts != null)
{
_penContexts = penContexts;
lock(penContexts.SyncRoot)
{
penContexts.AddStylusPlugInCollection(this);
foreach (StylusPlugIn spi in this)
{
spi.InvalidateIsActiveForInput(); // Uses _penContexts being set to determine active state.
}
// NTRAID:WINDOWSOS#1677277-2006/06/05-WAYNEZEN,
// Normally the Rect will be updated when we receive the LayoutUpdate.
// However there could be a race condition which the LayoutUpdate gets received
// before the properties like IsVisible being set.
// So we should always force to call OnLayoutUpdated whenever the input is active.
OnLayoutUpdated(this, EventArgs.Empty);
}
}
}
}
}
if (unhookPenContexts)
{
UnhookPenContexts();
}
}
}
///
/// Critical - _penContexts access
/// TreatAsSafe:
/// - no data handed out or accepted
///
[SecurityCritical,SecurityTreatAsSafe]
void UnhookPenContexts()
{
// Are we currently unhooked? If not then unhook.
if (_penContexts != null)
{
lock(_penContexts.SyncRoot)
{
_penContexts.RemoveStylusPlugInCollection(this);
// Can't recieve any more input now!
_penContexts = null;
// Notify after input is disabled to the PlugIns.
foreach (StylusPlugIn spi in this)
{
spi.InvalidateIsActiveForInput();
}
}
}
}
#endregion
#region Fields
private UIElement _element;
private Rect _rc; // In window root measured units
private GeneralTransform _viewToElement;
private Transform _lastRenderTransform;
// Note that this is only set when the Element is in a state to receive input (visible,enabled,in tree).
///
/// Critical to prevent accidental spread to transparent code
///
[SecurityCritical]
private PenContexts _penContexts;
private DependencyPropertyChangedEventHandler _isEnabledChangedEventHandler;
private DependencyPropertyChangedEventHandler _isVisibleChangedEventHandler;
private DependencyPropertyChangedEventHandler _isHitTestVisibleChangedEventHandler;
private EventHandler _renderTransformChangedEventHandler;
private SourceChangedEventHandler _sourceChangedEventHandler;
private EventHandler _layoutChangedEventHandler;
#endregion
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SystemColors.cs
- AmbientLight.cs
- WsatEtwTraceListener.cs
- ProcessProtocolHandler.cs
- DefinitionUpdate.cs
- RegexReplacement.cs
- ClassicBorderDecorator.cs
- RecipientServiceModelSecurityTokenRequirement.cs
- MenuBindingsEditorForm.cs
- IPAddress.cs
- GenericEnumConverter.cs
- ProcessHostMapPath.cs
- CodeCatchClauseCollection.cs
- DynamicFilterExpression.cs
- ActionFrame.cs
- Int32CollectionValueSerializer.cs
- XmlResolver.cs
- DataBindingList.cs
- SignatureHelper.cs
- Bold.cs
- Metafile.cs
- GatewayIPAddressInformationCollection.cs
- IUnknownConstantAttribute.cs
- PhysicalAddress.cs
- DrawingCollection.cs
- SamlNameIdentifierClaimResource.cs
- ArrangedElement.cs
- QueryConverter.cs
- QueryOperationResponseOfT.cs
- BevelBitmapEffect.cs
- TextWriterTraceListener.cs
- ResolveMatchesMessage11.cs
- DockPanel.cs
- XmlSchemaSimpleContentExtension.cs
- PropertyGridView.cs
- HyperLinkStyle.cs
- DrawingVisualDrawingContext.cs
- AxisAngleRotation3D.cs
- LabelAutomationPeer.cs
- SqlBooleanMismatchVisitor.cs
- RangeBaseAutomationPeer.cs
- validationstate.cs
- sqlser.cs
- RoutedUICommand.cs
- CollectionTypeElement.cs
- IUnknownConstantAttribute.cs
- HtmlTableCellCollection.cs
- URIFormatException.cs
- PersonalizationProviderHelper.cs
- CacheModeValueSerializer.cs
- TextServicesLoader.cs
- ItemCheckedEvent.cs
- KeyboardNavigation.cs
- TdsParserSafeHandles.cs
- NativeCppClassAttribute.cs
- DependencyPropertyChangedEventArgs.cs
- SoapAttributeAttribute.cs
- SoapInteropTypes.cs
- RuleInfoComparer.cs
- Quaternion.cs
- PersonalizationStateInfo.cs
- BamlLocalizabilityResolver.cs
- BufferAllocator.cs
- AppSettingsExpressionBuilder.cs
- ListViewItemEventArgs.cs
- SplayTreeNode.cs
- SequenceDesigner.cs
- Cursors.cs
- HorizontalAlignConverter.cs
- ByteFacetDescriptionElement.cs
- ImageList.cs
- GlyphInfoList.cs
- DatagridviewDisplayedBandsData.cs
- ScrollPatternIdentifiers.cs
- ButtonFlatAdapter.cs
- WebRequest.cs
- HyperLinkColumn.cs
- Clock.cs
- LinkedList.cs
- PartialTrustVisibleAssembly.cs
- ContactManager.cs
- Point4D.cs
- SecurityManager.cs
- SqlBulkCopy.cs
- TextTreeUndo.cs
- LinkArea.cs
- PnrpPeerResolverElement.cs
- OracleCommandSet.cs
- NonParentingControl.cs
- EntityModelSchemaGenerator.cs
- Types.cs
- _CacheStreams.cs
- Span.cs
- CodeEventReferenceExpression.cs
- XhtmlBasicImageAdapter.cs
- RSAOAEPKeyExchangeFormatter.cs
- SqlError.cs
- CharacterMetricsDictionary.cs
- DataContract.cs
- ScrollableControl.cs