File 0001-UIAutomationClient-AutomationElement.FromLocalProvid.patch of Package mono-uia

From 379d89f7ab15ee443d9a164d193f5e9bf3285b69 Mon Sep 17 00:00:00 2001
From: Mario Carrion <mcarrion@novell.com>
Date: Tue, 16 Nov 2010 17:01:32 -0500
Subject: [UIAutomationClient] AutomationElement.FromLocalProvider
 implementation.

Fixes BNC #489388 and building with Mono 2.8
---
 MoonAtkBridge/MoonAtkBridge.sln                    |    5 +-
 UIAutomation/UIAutomationBridge/Makefile.am        |    1 +
 .../Mono.UIAutomation.Services/ArgumentCheck.cs    |   42 ++
 .../UIAutomationBridge/UIAutomationBridge.csproj   |    1 +
 UIAutomation/UIAutomationClient/Makefile.am        |    7 +
 .../ClientAutomationBridge.cs                      |   87 ++++
 .../ClientAutomationSource.cs                      |  184 +++++++
 .../ClientElement.cs                               |  514 ++++++++++++++++++++
 .../ClientEventManager.cs                          |  250 ++++++++++
 .../ClientInvokePattern.cs                         |   50 ++
 .../System.Windows.Automation/Automation.cs        |   60 +--
 .../System.Windows.Automation/AutomationElement.cs |   14 +-
 .../System.Windows.Automation/ClientSettings.cs    |    4 +-
 .../ClientSideProviderDescription.cs               |   26 +-
 .../System.Windows.Automation/SourceManager.cs     |    2 +
 .../UIAutomationClient/UIAutomationClient.csproj   |    8 +
 .../UIAutomationClientTests/BaseTest.cs            |    2 +
 .../UIAutomationClientTests/LocalProviderTest.cs   |  172 ++++++-
 .../UIAutomationClientTests.csproj                 |   15 +-
 .../AutomationInteropProvider.cs                   |    7 +-
 .../AutomationIdentifier.cs                        |    6 +-
 UiaAtkBridge/Test/AtkTest/AtkTest.csproj           |    1 +
 UiaAtkBridge/Test/GailTestApp/gtk-gui/generated.cs |   55 +--
 .../Wrappers/ProviderElementWrapper.cs             |   16 +-
 UiaDbus/UiaDbusSource/UiaDbusElement.cs            |    2 +-
 uia2atk.mdw                                        |    2 +-
 26 files changed, 1419 insertions(+), 114 deletions(-)
 create mode 100644 UIAutomation/UIAutomationBridge/Mono.UIAutomation.Services/ArgumentCheck.cs
 create mode 100644 UIAutomation/UIAutomationClient/Mono.UIAutomation.ClientSource/ClientAutomationBridge.cs
 create mode 100644 UIAutomation/UIAutomationClient/Mono.UIAutomation.ClientSource/ClientAutomationSource.cs
 create mode 100644 UIAutomation/UIAutomationClient/Mono.UIAutomation.ClientSource/ClientElement.cs
 create mode 100644 UIAutomation/UIAutomationClient/Mono.UIAutomation.ClientSource/ClientEventManager.cs
 create mode 100644 UIAutomation/UIAutomationClient/Mono.UIAutomation.ClientSource/ClientInvokePattern.cs

Index: mono-uia.git/UIAutomationBridge/Makefile.am
===================================================================
--- mono-uia.git.orig/UIAutomationBridge/Makefile.am	2012-01-23 18:58:34.192473338 +0000
+++ mono-uia.git/UIAutomationBridge/Makefile.am	2012-01-23 18:58:44.776520265 +0000
@@ -28,6 +28,7 @@
 PROJECT_SOURCE_FILES =  \
 	Mono.UIAutomation.Bridge/IAutomationBridge.cs \
 	Mono.UIAutomation.Bridge/IHypertext.cs \
+	Mono.UIAutomation.Services/ArgumentCheck.cs \
 	Mono.UIAutomation.Services/Log.cs
 
 FILES =  \
Index: mono-uia.git/UIAutomationBridge/Mono.UIAutomation.Services/ArgumentCheck.cs
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ mono-uia.git/UIAutomationBridge/Mono.UIAutomation.Services/ArgumentCheck.cs	2012-01-23 18:58:44.776520265 +0000
@@ -0,0 +1,42 @@
+// Permission is hereby granted, free of charge, to any person obtaining 
+// a copy of this software and associated documentation files (the 
+// "Software"), to deal in the Software without restriction, including 
+// without limitation the rights to use, copy, modify, merge, publish, 
+// distribute, sublicense, and/or sell copies of the Software, and to 
+// permit persons to whom the Software is furnished to do so, subject to 
+// the following conditions: 
+//  
+// The above copyright notice and this permission notice shall be 
+// included in all copies or substantial portions of the Software. 
+//  
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
+// 
+// Copyright (c) 2010 Novell, Inc. (http://www.novell.com) 
+// 
+// Authors: 
+//      Matt Guo <matt@mattguo.com>
+// 
+
+using System;
+
+namespace Mono.UIAutomation.Services
+{
+	public static class ArgumentCheck
+	{
+		public static void NotNull<T> (T arg, string argName) where T : class {
+			if (arg == null)
+				throw new ArgumentNullException (argName);
+		}
+
+		public static void Assert<T> (T arg, Predicate<T> condition, string errorMessage) {
+			if (!condition (arg))
+				throw new ArgumentException (errorMessage);
+		}
+	}
+}
Index: mono-uia.git/UIAutomationClient/Makefile.am
===================================================================
--- mono-uia.git.orig/UIAutomationClient/Makefile.am	2012-01-23 18:58:34.192473338 +0000
+++ mono-uia.git/UIAutomationClient/Makefile.am	2012-01-23 18:58:44.780520283 +0000
@@ -31,6 +31,11 @@
 all: $(ASSEMBLY) $(PROGRAMFILES)
 
 PROJECT_SOURCE_FILES =  \
+	Mono.UIAutomation.ClientSource/ClientAutomationBridge.cs \
+	Mono.UIAutomation.ClientSource/ClientAutomationSource.cs \
+	Mono.UIAutomation.ClientSource/ClientElement.cs \
+	Mono.UIAutomation.ClientSource/ClientEventManager.cs \
+	Mono.UIAutomation.ClientSource/ClientInvokePattern.cs \
 	System.Windows.Automation.Text/TextPatternRange.cs \
 	System.Windows.Automation/AndCondition.cs \
 	System.Windows.Automation/Automation.cs \
@@ -84,6 +89,8 @@
 REFERENCES =  \
 	WindowsBase \
 	System \
+	System.Core \
+	Mono.Posix \
 	$(GTK_SHARP_20_LIBS)
 
 DLL_REFERENCES = 
Index: mono-uia.git/UIAutomationClient/Mono.UIAutomation.ClientSource/ClientAutomationBridge.cs
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ mono-uia.git/UIAutomationClient/Mono.UIAutomation.ClientSource/ClientAutomationBridge.cs	2012-01-23 18:58:44.780520283 +0000
@@ -0,0 +1,87 @@
+// Permission is hereby granted, free of charge, to any person obtaining 
+// a copy of this software and associated documentation files (the 
+// "Software"), to deal in the Software without restriction, including 
+// without limitation the rights to use, copy, modify, merge, publish, 
+// distribute, sublicense, and/or sell copies of the Software, and to 
+// permit persons to whom the Software is furnished to do so, subject to 
+// the following conditions: 
+//  
+// The above copyright notice and this permission notice shall be 
+// included in all copies or substantial portions of the Software. 
+//  
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
+// 
+// Copyright (c) 2010 Novell, Inc. (http://www.novell.com) 
+// 
+// Authors: 
+//     Matt Guo <matt@mattguo.com>
+// 
+
+using System;
+using System.Windows.Automation;
+using System.Windows.Automation.Provider;
+using Mono.UIAutomation.Bridge;
+
+namespace Mono.UIAutomation.ClientSource
+{
+	internal class ClientAutomationBridge : IAutomationBridge
+	{
+		#region IAutomationBridge implementation
+		public object HostProviderFromHandle (IntPtr hwnd)
+		{
+			return null;
+		}
+
+		public void RaiseAutomationEvent (AutomationEvent eventId, object provider, AutomationEventArgs e)
+		{
+			var providerSimple = provider as IRawElementProviderSimple;
+			if (providerSimple == null)
+				return;
+			ClientEventManager.RaiseAutomationEvent (eventId, providerSimple, e);
+		}
+
+		public void RaiseAutomationPropertyChangedEvent (object provider, AutomationPropertyChangedEventArgs e)
+		{
+			var providerSimple = provider as IRawElementProviderSimple;
+			if (providerSimple == null)
+				return;
+			ClientEventManager.RaiseAutomationPropertyChangedEvent (providerSimple, e);
+		}
+
+		public void RaiseStructureChangedEvent (object provider, StructureChangedEventArgs e)
+		{
+			var providerSimple = provider as IRawElementProviderSimple;
+			if (providerSimple == null)
+				return;
+			ClientEventManager.RaiseStructureChangedEvent (providerSimple, e);
+		}
+
+		public void Initialize ()
+		{
+		}
+
+		public void Terminate ()
+		{
+		}
+
+		public bool IsAccessibilityEnabled {
+			get {
+				return true;
+			}
+		}
+
+		public bool ClientsAreListening {
+			get {
+				return true;
+			}
+		}
+
+		#endregion
+	}
+}
Index: mono-uia.git/UIAutomationClient/Mono.UIAutomation.ClientSource/ClientAutomationSource.cs
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ mono-uia.git/UIAutomationClient/Mono.UIAutomation.ClientSource/ClientAutomationSource.cs	2012-01-23 18:58:44.780520283 +0000
@@ -0,0 +1,184 @@
+// Permission is hereby granted, free of charge, to any person obtaining 
+// a copy of this software and associated documentation files (the 
+// "Software"), to deal in the Software without restriction, including 
+// without limitation the rights to use, copy, modify, merge, publish, 
+// distribute, sublicense, and/or sell copies of the Software, and to 
+// permit persons to whom the Software is furnished to do so, subject to 
+// the following conditions: 
+//  
+// The above copyright notice and this permission notice shall be 
+// included in all copies or substantial portions of the Software. 
+//  
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
+// 
+// Copyright (c) 2010 Novell, Inc. (http://www.novell.com) 
+// 
+// Authors: 
+//     Matt Guo <matt@mattguo.com>
+// 
+
+using System;
+using System.Threading;
+using System.Windows.Automation;
+using System.Windows.Automation.Provider;
+using Mono.UIAutomation.Source;
+using Mono.UIAutomation.Services;
+
+namespace Mono.UIAutomation.ClientSource
+{
+	internal class ClientAutomationSource : IAutomationSource
+	{
+		private static ClientAutomationSource instance = null;
+		private static object staticLock = new object ();
+		public static ClientAutomationSource Instance {
+			get {
+				if (instance == null)
+					lock (staticLock)
+						if (instance == null)
+							instance = new ClientAutomationSource ();
+				return instance;
+			}
+		}
+
+		#region IAutomationSource implementation
+		public event EventHandler RootElementsChanged;
+
+		public void Initialize ()
+		{
+		}
+
+		public IElement [] GetRootElements ()
+		{
+			return new IElement [0];
+		}
+
+		public IElement GetFocusedElement ()
+		{
+			return null;
+		}
+
+		public IElement GetElementFromHandle (IntPtr handle)
+		{
+			return null;
+		}
+
+		public void AddAutomationEventHandler (AutomationEvent eventId, IElement element, TreeScope scope, AutomationEventHandler eventHandler)
+		{
+			if (element == null)
+				// elements from local providers are not descendants of the RootElement.
+				return;
+			ClientElement clientElement = element as ClientElement;
+			if (clientElement == null) {
+				Log.Error ("[ClientAutomationSource.AddAutomationEventHandler] Not ClientElement");
+				return;
+			}
+			ClientEventManager.AddAutomationEventHandler (eventId,
+				clientElement.Provider, scope, eventHandler);
+		}
+
+		public void AddAutomationPropertyChangedEventHandler (IElement element, TreeScope scope, AutomationPropertyChangedEventHandler eventHandler, AutomationProperty[] properties)
+		{
+			if (element == null)
+				return;
+			ClientElement clientElement = element as ClientElement;
+			if (clientElement == null) {
+				Log.Error ("[ClientAutomationSource.AddAutomationPropertyChangedEventHandler] Not ClientElement");
+				return;
+			}
+			int [] propertyIds = Array.ConvertAll (properties, p => p.Id);
+			ClientEventManager.AddAutomationPropertyChangedEventHandler (
+				clientElement.Provider, scope, eventHandler, propertyIds);
+		}
+
+		public void AddStructureChangedEventHandler (IElement element, TreeScope scope, StructureChangedEventHandler eventHandler)
+		{
+			if (element == null)
+				return;
+			ClientElement clientElement = element as ClientElement;
+			if (clientElement == null) {
+				Log.Error ("[ClientAutomationSource.AddStructureChangedEventHandler] Not ClientElement");
+				return;
+			}
+			ClientEventManager.AddStructureChangedEventHandler (clientElement.Provider,
+				scope, eventHandler);
+		}
+
+		public void AddAutomationFocusChangedEventHandler (FocusChangedEventHandler eventHandler)
+		{
+			// client provider never fires FocusChangedEvent.
+			return;
+		}
+
+		public void RemoveAutomationEventHandler (AutomationEvent eventId, IElement element, AutomationEventHandler eventHandler)
+		{
+			if (element == null)
+				return;
+			ClientElement clientElement = element as ClientElement;
+			if (clientElement == null) {
+				Log.Error ("[ClientAutomationSource.RemoveAutomationEventHandler] Not ClientElement");
+				return;
+			}
+			ClientEventManager.RemoveAutomationEventHandler (eventId,
+				clientElement.Provider, eventHandler);
+		}
+
+		public void RemoveAutomationPropertyChangedEventHandler (IElement element, AutomationPropertyChangedEventHandler eventHandler)
+		{
+			if (element == null)
+				return;
+			ClientElement clientElement = element as ClientElement;
+			if (clientElement == null) {
+				Log.Error ("[ClientAutomationSource.RemoveAutomationPropertyChangedEventHandler] Not ClientElement");
+				return;
+			}
+			ClientEventManager.RemoveAutomationPropertyChangedEventHandler (
+				clientElement.Provider, eventHandler);
+		}
+
+		public void RemoveStructureChangedEventHandler (IElement element, StructureChangedEventHandler eventHandler)
+		{
+			if (element == null)
+				return;
+			ClientElement clientElement = element as ClientElement;
+			if (clientElement == null) {
+				Log.Error ("[ClientAutomationSource.RemoveStructureChangedEventHandler] Not ClientElement");
+				return;
+			}
+			ClientEventManager.RemoveStructureChangedEventHandler (
+				clientElement.Provider, eventHandler);
+		}
+
+		public void RemoveAutomationFocusChangedEventHandler (FocusChangedEventHandler eventHandler)
+		{
+			// client provider never fires FocusChangedEvent.
+			return;
+		}
+
+		public void RemoveAllEventHandlers ()
+		{
+			ClientEventManager.RemoveAllEventHandlers ();
+		}
+
+		public bool IsAccessibilityEnabled {
+			get {
+				return true;
+			}
+		}
+
+		#endregion
+
+		public ClientElement GetOrCreateElement (IRawElementProviderSimple provider)
+		{
+			if (provider == null)
+				return null;
+			//?????
+			return new ClientElement (this, provider);
+		}
+	}
+}
\ No newline at end of file
Index: mono-uia.git/UIAutomationClient/Mono.UIAutomation.ClientSource/ClientElement.cs
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ mono-uia.git/UIAutomationClient/Mono.UIAutomation.ClientSource/ClientElement.cs	2012-01-23 18:58:44.780520283 +0000
@@ -0,0 +1,514 @@
+// Permission is hereby granted, free of charge, to any person obtaining 
+// a copy of this software and associated documentation files (the 
+// "Software"), to deal in the Software without restriction, including 
+// without limitation the rights to use, copy, modify, merge, publish, 
+// distribute, sublicense, and/or sell copies of the Software, and to 
+// permit persons to whom the Software is furnished to do so, subject to 
+// the following conditions: 
+//  
+// The above copyright notice and this permission notice shall be 
+// included in all copies or substantial portions of the Software. 
+//  
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
+// 
+// Copyright (c) 2010 Novell, Inc. (http://www.novell.com) 
+// 
+// Authors: 
+//     Matt Guo <matt@mattguo.com>
+// 
+
+using System;
+using System.Windows;
+using System.Windows.Automation;
+using System.Windows.Automation.Provider;
+using Mono.UIAutomation.Source;
+using AEIds = System.Windows.Automation.AutomationElementIdentifiers;
+using System.Collections.Generic;
+using Mono.Unix;
+using Mono.UIAutomation.Services;
+using System.Linq;
+
+namespace Mono.UIAutomation.ClientSource
+{
+	// TODO the ClientElement class shares many common code with UiaDbusBridge.ProviderElementWrapper,
+	// Any change to refactor and merge these code?
+	internal class ClientElement : IElement
+	{
+		#region All patterns and properties
+		private static int [] allPatternIds = {
+			ExpandCollapsePatternIdentifiers.Pattern.Id,
+			GridItemPatternIdentifiers.Pattern.Id,
+			GridPatternIdentifiers.Pattern.Id,
+			InvokePatternIdentifiers.Pattern.Id,
+			MultipleViewPatternIdentifiers.Pattern.Id,
+			RangeValuePatternIdentifiers.Pattern.Id,
+			ScrollPatternIdentifiers.Pattern.Id,
+			SelectionItemPatternIdentifiers.Pattern.Id,
+			SelectionPatternIdentifiers.Pattern.Id,
+			TablePatternIdentifiers.Pattern.Id,
+			TextPatternIdentifiers.Pattern.Id,
+			TogglePatternIdentifiers.Pattern.Id,
+			TransformPatternIdentifiers.Pattern.Id,
+			ValuePatternIdentifiers.Pattern.Id,
+			WindowPatternIdentifiers.Pattern.Id,
+			ScrollItemPatternIdentifiers.Pattern.Id,
+			DockPatternIdentifiers.Pattern.Id,
+			TableItemPatternIdentifiers.Pattern.Id
+		};
+
+		private static int [] allPropertyIds = {
+			AutomationElementIdentifiers.IsControlElementProperty.Id,
+			AutomationElementIdentifiers.ControlTypeProperty.Id,
+			AutomationElementIdentifiers.IsContentElementProperty.Id,
+			AutomationElementIdentifiers.LabeledByProperty.Id,
+			AutomationElementIdentifiers.NativeWindowHandleProperty.Id,
+			AutomationElementIdentifiers.AutomationIdProperty.Id,
+			AutomationElementIdentifiers.ItemTypeProperty.Id,
+			AutomationElementIdentifiers.IsPasswordProperty.Id,
+			AutomationElementIdentifiers.LocalizedControlTypeProperty.Id,
+			AutomationElementIdentifiers.NameProperty.Id,
+			AutomationElementIdentifiers.AcceleratorKeyProperty.Id,
+			AutomationElementIdentifiers.AccessKeyProperty.Id,
+			AutomationElementIdentifiers.HasKeyboardFocusProperty.Id,
+			AutomationElementIdentifiers.IsKeyboardFocusableProperty.Id,
+			AutomationElementIdentifiers.IsEnabledProperty.Id,
+			AutomationElementIdentifiers.BoundingRectangleProperty.Id,
+			AutomationElementIdentifiers.ProcessIdProperty.Id,
+			AutomationElementIdentifiers.RuntimeIdProperty.Id,
+			AutomationElementIdentifiers.ClassNameProperty.Id,
+			AutomationElementIdentifiers.HelpTextProperty.Id,
+			AutomationElementIdentifiers.ClickablePointProperty.Id,
+			AutomationElementIdentifiers.CultureProperty.Id,
+			AutomationElementIdentifiers.IsOffscreenProperty.Id,
+			AutomationElementIdentifiers.OrientationProperty.Id,
+			AutomationElementIdentifiers.FrameworkIdProperty.Id,
+			AutomationElementIdentifiers.IsRequiredForFormProperty.Id,
+			AutomationElementIdentifiers.ItemStatusProperty.Id,
+			// Comment Is*PatternAvailableProperty since MS.Net never include those
+			// properties in the return value of AutomationElement.GetSupportedProperties ()
+			//AutomationElementIdentifiers.IsDockPatternAvailableProperty.Id,
+			//AutomationElementIdentifiers.IsExpandCollapsePatternAvailableProperty.Id,
+			//AutomationElementIdentifiers.IsGridItemPatternAvailableProperty.Id,
+			//AutomationElementIdentifiers.IsGridPatternAvailableProperty.Id,
+			//AutomationElementIdentifiers.IsInvokePatternAvailableProperty.Id,
+			//AutomationElementIdentifiers.IsMultipleViewPatternAvailableProperty.Id,
+			//AutomationElementIdentifiers.IsRangeValuePatternAvailableProperty.Id,
+			//AutomationElementIdentifiers.IsSelectionItemPatternAvailableProperty.Id,
+			//AutomationElementIdentifiers.IsSelectionPatternAvailableProperty.Id,
+			//AutomationElementIdentifiers.IsScrollPatternAvailableProperty.Id,
+			//AutomationElementIdentifiers.IsScrollItemPatternAvailableProperty.Id,
+			//AutomationElementIdentifiers.IsTablePatternAvailableProperty.Id,
+			//AutomationElementIdentifiers.IsTableItemPatternAvailableProperty.Id,
+			//AutomationElementIdentifiers.IsTextPatternAvailableProperty.Id,
+			//AutomationElementIdentifiers.IsTogglePatternAvailableProperty.Id,
+			//AutomationElementIdentifiers.IsTransformPatternAvailableProperty.Id,
+			//AutomationElementIdentifiers.IsValuePatternAvailableProperty.Id,
+			//AutomationElementIdentifiers.IsWindowPatternAvailableProperty.Id,
+			ExpandCollapsePatternIdentifiers.ExpandCollapseStateProperty.Id,
+			GridItemPatternIdentifiers.RowProperty.Id,
+			GridItemPatternIdentifiers.ColumnProperty.Id,
+			GridItemPatternIdentifiers.RowSpanProperty.Id,
+			GridItemPatternIdentifiers.ColumnSpanProperty.Id,
+			GridItemPatternIdentifiers.ContainingGridProperty.Id,
+			GridPatternIdentifiers.RowCountProperty.Id,
+			GridPatternIdentifiers.ColumnCountProperty.Id,
+			MultipleViewPatternIdentifiers.CurrentViewProperty.Id,
+			MultipleViewPatternIdentifiers.SupportedViewsProperty.Id,
+			RangeValuePatternIdentifiers.ValueProperty.Id,
+			RangeValuePatternIdentifiers.IsReadOnlyProperty.Id,
+			RangeValuePatternIdentifiers.MinimumProperty.Id,
+			RangeValuePatternIdentifiers.MaximumProperty.Id,
+			RangeValuePatternIdentifiers.LargeChangeProperty.Id,
+			RangeValuePatternIdentifiers.SmallChangeProperty.Id,
+			ScrollPatternIdentifiers.HorizontalScrollPercentProperty.Id,
+			ScrollPatternIdentifiers.HorizontalViewSizeProperty.Id,
+			ScrollPatternIdentifiers.VerticalScrollPercentProperty.Id,
+			ScrollPatternIdentifiers.VerticalViewSizeProperty.Id,
+			ScrollPatternIdentifiers.HorizontallyScrollableProperty.Id,
+			ScrollPatternIdentifiers.VerticallyScrollableProperty.Id,
+			SelectionItemPatternIdentifiers.IsSelectedProperty.Id,
+			SelectionItemPatternIdentifiers.SelectionContainerProperty.Id,
+			SelectionPatternIdentifiers.SelectionProperty.Id,
+			SelectionPatternIdentifiers.CanSelectMultipleProperty.Id,
+			SelectionPatternIdentifiers.IsSelectionRequiredProperty.Id,
+			TablePatternIdentifiers.RowHeadersProperty.Id,
+			TablePatternIdentifiers.ColumnHeadersProperty.Id,
+			TablePatternIdentifiers.RowOrColumnMajorProperty.Id,
+			TogglePatternIdentifiers.ToggleStateProperty.Id,
+			TransformPatternIdentifiers.CanMoveProperty.Id,
+			TransformPatternIdentifiers.CanResizeProperty.Id,
+			TransformPatternIdentifiers.CanRotateProperty.Id,
+			ValuePatternIdentifiers.ValueProperty.Id,
+			ValuePatternIdentifiers.IsReadOnlyProperty.Id,
+			WindowPatternIdentifiers.CanMaximizeProperty.Id,
+			WindowPatternIdentifiers.CanMinimizeProperty.Id,
+			WindowPatternIdentifiers.IsModalProperty.Id,
+			WindowPatternIdentifiers.WindowVisualStateProperty.Id,
+			WindowPatternIdentifiers.WindowInteractionStateProperty.Id,
+			WindowPatternIdentifiers.IsTopmostProperty.Id,
+			DockPatternIdentifiers.DockPositionProperty.Id,
+			TableItemPatternIdentifiers.RowHeaderItemsProperty.Id,
+			TableItemPatternIdentifiers.ColumnHeaderItemsProperty.Id
+		};
+		#endregion
+
+		#region Private FIelds
+
+		private ClientAutomationSource source = null;
+		private IRawElementProviderSimple provider = null;
+		private IRawElementProviderFragment providerFragment = null;
+		private IRawElementProviderFragmentRoot providerFragmentRoot = null;
+
+		#endregion
+
+		#region Constructor
+
+		public ClientElement (ClientAutomationSource source, IRawElementProviderSimple provider)
+		{
+			ArgumentCheck.NotNull (source, "source");
+			ArgumentCheck.NotNull (provider, "provider");
+
+			this.source = source;
+			this.provider = provider;
+			providerFragment = provider as IRawElementProviderFragment;
+			providerFragmentRoot = provider as IRawElementProviderFragmentRoot;
+		}
+
+		#endregion
+
+		internal IRawElementProviderSimple Provider {
+			get { return provider; }
+		}
+
+		#region IElement implementation
+
+		public bool SupportsProperty (AutomationProperty property)
+		{
+			ArgumentCheck.NotNull (property, "property");
+
+			object val = provider.GetPropertyValue (property.Id);
+			return val != null && val != AEIds.NotSupported;
+		}
+
+		public object GetCurrentPattern (AutomationPattern pattern)
+		{
+			ArgumentCheck.NotNull (pattern, "pattern");
+
+			var patternProvider = provider.GetPatternProvider (pattern.Id);
+			if (patternProvider == null)
+				throw new InvalidOperationException ();
+			object ret = null;
+			if (pattern == InvokePattern.Pattern)
+				ret = new ClientInvokePattern ((IInvokeProvider) patternProvider);
+			// TODO implement
+			// we still have more pattern to implement
+			else
+				throw new System.InvalidOperationException ();
+			return ret;
+		}
+
+		public AutomationPattern[] GetSupportedPatterns ()
+		{
+			return (from patternId in allPatternIds
+				where provider.GetPatternProvider (patternId) != null
+				select AutomationPattern.LookupById (patternId)).ToArray ();
+		}
+
+		public AutomationProperty[] GetSupportedProperties ()
+		{
+			return (from propertyId in allPropertyIds
+			        let val = provider.GetPropertyValue (propertyId)
+				where val != null && val != AEIds.NotSupported
+				select AutomationProperty.LookupById (propertyId)).ToArray ();
+		}
+
+		public void SetFocus ()
+		{
+			if (!IsKeyboardFocusable)
+				// as tested on Windows, the InvalidOperationException hasn't any error message 
+				throw new InvalidOperationException ();
+			if (providerFragment != null)
+				providerFragment.SetFocus ();
+		}
+
+		public IElement GetDescendantFromPoint (double x, double y)
+		{
+			if (providerFragmentRoot != null) {
+				var childProvider =
+					providerFragmentRoot.ElementProviderFromPoint (x, y);
+				return source.GetOrCreateElement (childProvider);
+			}
+			return null;
+		}
+
+		public string AcceleratorKey {
+			get {
+				return provider.GetPropertyValue (AEIds.AcceleratorKeyProperty.Id)
+					as string ?? string.Empty;
+			}
+		}
+
+		public string AccessKey {
+			get {
+				return provider.GetPropertyValue (AEIds.AccessKeyProperty.Id)
+					as string ?? string.Empty;
+			}
+		}
+
+		public string AutomationId {
+			get {
+				return provider.GetPropertyValue (AEIds.AutomationIdProperty.Id)
+					as string ?? string.Empty;
+			}
+		}
+
+		public Rect BoundingRectangle {
+			get {
+				// As tested on Windows, runtime id is solely decided
+				// by providerFragment.BoundingRectangle, and is irrelevant with
+				// IRawElementProviderSimple.GetPropertyValue (AEIds.BoundingRectangleProperty)
+
+				if (providerFragment != null)
+					return providerFragment.BoundingRectangle;
+				else
+					return Rect.Empty;
+			}
+		}
+
+		public string ClassName {
+			get {
+				return provider.GetPropertyValue (AEIds.ClassNameProperty.Id)
+					as string ?? string.Empty;
+			}
+		}
+
+		public Point ClickablePoint {
+			get {
+				object obj = provider.GetPropertyValue (AEIds.ClickablePointProperty.Id);
+				return (obj != null) ? (Point) obj :
+					new Point (double.NegativeInfinity, double.NegativeInfinity);
+			}
+		}
+
+		public ControlType ControlType {
+			get {
+				object obj = provider.GetPropertyValue (AEIds.ControlTypeProperty.Id);
+				return (obj != null) ? ControlType.LookupById ((int) obj) : ControlType.Custom;
+			}
+		}
+
+		public string FrameworkId {
+			get {
+				return provider.GetPropertyValue (AEIds.FrameworkIdProperty.Id)
+					as string ?? string.Empty;
+			}
+		}
+
+		public bool HasKeyboardFocus {
+			get {
+				object obj = provider.GetPropertyValue (AEIds.HasKeyboardFocusProperty.Id);
+				return (obj != null) ? (bool) obj : false;
+			}
+		}
+
+		public string HelpText {
+			get {
+				return provider.GetPropertyValue (AEIds.HelpTextProperty.Id)
+					as string ?? string.Empty;
+			}
+		}
+
+		public bool IsContentElement {
+			get {
+				object obj = provider.GetPropertyValue (AEIds.IsContentElementProperty.Id);
+				return (obj != null) ? (bool) obj : false;
+			}
+		}
+
+		public bool IsControlElement {
+			get {
+				object obj = provider.GetPropertyValue (AEIds.IsControlElementProperty.Id);
+				return (obj != null) ? (bool) obj : false;
+			}
+		}
+
+		public bool IsEnabled {
+			get {
+				object obj = provider.GetPropertyValue (AEIds.IsEnabledProperty.Id);
+				return (obj != null) ? (bool) obj : false;
+			}
+		}
+
+		public bool IsKeyboardFocusable {
+			get {
+				object obj = provider.GetPropertyValue (AEIds.IsKeyboardFocusableProperty.Id);
+				return (obj != null) ? (bool) obj : false;
+			}
+		}
+
+		public bool IsOffscreen {
+			get {
+				object obj = provider.GetPropertyValue (AEIds.IsOffscreenProperty.Id);
+				return (obj != null) ? (bool) obj : false;
+			}
+		}
+
+		public bool IsPassword {
+			get {
+				object obj = provider.GetPropertyValue (AEIds.IsPasswordProperty.Id);
+				return (obj != null) ? (bool) obj : false;
+			}
+		}
+
+		public bool IsRequiredForForm {
+			get {
+				object obj = provider.GetPropertyValue (AEIds.IsRequiredForFormProperty.Id);
+				return (obj != null) ? (bool) obj : false;
+			}
+		}
+
+		public string ItemStatus {
+			get {
+				return provider.GetPropertyValue (AEIds.ItemStatusProperty.Id)
+					as string ?? string.Empty;
+			}
+		}
+
+		public string ItemType {
+			get {
+				return provider.GetPropertyValue (AEIds.ItemTypeProperty.Id)
+					as string ?? string.Empty;
+			}
+		}
+
+		public IElement LabeledBy {
+			get {
+				var labeledBy = provider.GetPropertyValue (AEIds.LabeledByProperty.Id)
+					as IRawElementProviderSimple;
+				return (labeledBy != null) ? source.GetOrCreateElement (labeledBy) : null;
+			}
+		}
+
+		public string LocalizedControlType {
+			get {
+				var controlType = this.ControlType;
+				if (controlType == ControlType.DataGrid)
+					return Catalog.GetString ("data grid");
+				else if (controlType == ControlType.DataItem)
+					return Catalog.GetString ("data item");
+				else if (controlType == ControlType.List)
+					return Catalog.GetString ("list");
+				else
+					return controlType.LocalizedControlType;
+			}
+		}
+
+		public string Name {
+			get {
+				return provider.GetPropertyValue (AEIds.NameProperty.Id)
+					as string ?? string.Empty;
+			}
+		}
+
+		public int NativeWindowHandle {
+			get {
+				object obj = provider.GetPropertyValue (AEIds.NativeWindowHandleProperty.Id);
+				return (obj != null) ? (int) obj : 0;
+			}
+		}
+
+		public OrientationType Orientation {
+			get {
+				object obj = provider.GetPropertyValue (AEIds.OrientationProperty.Id);
+				return (obj != null) ? (OrientationType) obj : OrientationType.None;
+			}
+		}
+
+		public int ProcessId {
+			get {
+				object obj = provider.GetPropertyValue (AEIds.ProcessIdProperty.Id);
+				return (obj != null) ? (int) obj : 0;
+			}
+		}
+
+		public int[] RuntimeId {
+			get {
+				// As tested on Windows, runtime id is solely decided
+				// by providerFragment.GetRuntimeId, and is irrelevant with
+				// IRawElementProviderSimple.GetPropertyValue (AEIds.RuntimeIdProperty)
+				//
+				// An expcetion: if the runtime id is not explicitly provided, while
+				// native handle is provided, then UIA will generate a runtime id for the provider,
+				// on Windows 7 the runtime id is [42, NativeHandleValue]
+				int [] runtimeId = null;
+				if (providerFragment != null)
+					runtimeId = providerFragment.GetRuntimeId ();
+				else {
+					int hwnd = this.NativeWindowHandle;
+					if (hwnd != 0)
+						runtimeId = new int [] {42, hwnd};
+				}
+				return runtimeId;
+			}
+		}
+
+		public IElement Parent {
+			get {
+				if (providerFragment == null)
+					return null;
+				return source.GetOrCreateElement (
+					providerFragment.Navigate (NavigateDirection.Parent));
+			}
+		}
+
+		public IElement FirstChild {
+			get {
+				if (providerFragment == null)
+					return null;
+				return source.GetOrCreateElement (
+					providerFragment.Navigate (NavigateDirection.FirstChild));
+			}
+		}
+
+		public IElement LastChild {
+			get {
+				if (providerFragment == null)
+					return null;
+				return source.GetOrCreateElement (
+					providerFragment.Navigate (NavigateDirection.LastChild));
+			}
+		}
+
+		public IElement NextSibling {
+			get {
+				if (providerFragment == null)
+					return null;
+				return source.GetOrCreateElement (
+					providerFragment.Navigate (NavigateDirection.NextSibling));
+			}
+		}
+
+		public IElement PreviousSibling {
+			get {
+				if (providerFragment == null)
+					return null;
+				return source.GetOrCreateElement (
+					providerFragment.Navigate (NavigateDirection.PreviousSibling));
+			}
+		}
+
+		public IAutomationSource AutomationSource {
+			get {
+				return source;
+			}
+		}
+
+		#endregion
+	}
+}
Index: mono-uia.git/UIAutomationClient/Mono.UIAutomation.ClientSource/ClientEventManager.cs
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ mono-uia.git/UIAutomationClient/Mono.UIAutomation.ClientSource/ClientEventManager.cs	2012-01-23 18:58:44.780520283 +0000
@@ -0,0 +1,250 @@
+// Permission is hereby granted, free of charge, to any person obtaining 
+// a copy of this software and associated documentation files (the 
+// "Software"), to deal in the Software without restriction, including 
+// without limitation the rights to use, copy, modify, merge, publish, 
+// distribute, sublicense, and/or sell copies of the Software, and to 
+// permit persons to whom the Software is furnished to do so, subject to 
+// the following conditions: 
+//  
+// The above copyright notice and this permission notice shall be 
+// included in all copies or substantial portions of the Software. 
+//  
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
+// 
+// Copyright (c) 2010 Novell, Inc. (http://www.novell.com) 
+// 
+// Authors: 
+//     Matt Guo <matt@mattguo.com>
+// 
+
+using System;
+using System.Collections.Generic;
+using System.Windows.Automation;
+using System.Windows.Automation.Provider;
+using Mono.UIAutomation.Source;
+
+namespace Mono.UIAutomation.ClientSource
+{
+	internal static class ClientEventManager
+	{
+		private static List<PropertyChangedEventEntry> propertyChangedEventEntries
+			= new List<PropertyChangedEventEntry> ();
+		private static List<AutomationEventEntry> automationEventEntries
+			= new List<AutomationEventEntry> ();
+		private static List<StructureChangedEventEntry> structureChangedEventEntries
+			= new List<StructureChangedEventEntry> ();
+
+		public static void AddAutomationEventHandler (AutomationEvent eventId,
+			IRawElementProviderSimple provider, TreeScope scope,
+			AutomationEventHandler eventHandler)
+		{
+			var entry = new AutomationEventEntry (eventId, provider, scope, eventHandler);
+			lock (automationEventEntries)
+				automationEventEntries.Add (entry);
+		}
+
+		public static void AddAutomationPropertyChangedEventHandler (
+			IRawElementProviderSimple provider, TreeScope scope,
+			AutomationPropertyChangedEventHandler eventHandler,
+			int [] properties)
+		{
+			var entry = new PropertyChangedEventEntry (provider, scope, properties, eventHandler);
+			lock (propertyChangedEventEntries)
+				propertyChangedEventEntries.Add (entry);
+		}
+
+		public static void AddStructureChangedEventHandler (
+			IRawElementProviderSimple provider, TreeScope scope,
+			StructureChangedEventHandler eventHandler)
+		{
+			var entry = new StructureChangedEventEntry (provider, scope, eventHandler);
+			lock (structureChangedEventEntries)
+				structureChangedEventEntries.Add (entry);
+		}
+
+		public static void RemoveAutomationEventHandler (AutomationEvent eventId, IRawElementProviderSimple provider, AutomationEventHandler eventHandler)
+		{
+			lock (automationEventEntries)
+				automationEventEntries.RemoveAll (e =>
+					e.EventId == eventId &&
+					e.Provider == provider &&
+					e.Handler == eventHandler);
+		}
+
+		public static void RemoveAutomationPropertyChangedEventHandler (IRawElementProviderSimple provider, AutomationPropertyChangedEventHandler eventHandler)
+		{
+			lock (propertyChangedEventEntries)
+				propertyChangedEventEntries.RemoveAll (e =>
+					e.Provider == provider &&
+					e.Handler == eventHandler);
+		}
+
+		public static void RemoveStructureChangedEventHandler (IRawElementProviderSimple provider, StructureChangedEventHandler eventHandler)
+		{
+			lock (structureChangedEventEntries)
+				structureChangedEventEntries.RemoveAll (e =>
+					e.Provider == provider &&
+					e.Handler == eventHandler);
+		}
+
+		public static void RemoveAllEventHandlers ()
+		{
+			lock (automationEventEntries)
+				automationEventEntries.Clear ();
+			lock (structureChangedEventEntries)
+				structureChangedEventEntries.Clear ();
+			lock (propertyChangedEventEntries)
+				propertyChangedEventEntries.Clear ();
+		}
+
+		public static void RaiseAutomationEvent (AutomationEvent eventId,
+			IRawElementProviderSimple provider, AutomationEventArgs e)
+		{
+			lock (automationEventEntries)
+				foreach (var entry in automationEventEntries)
+					if (entry.EventId == eventId &&
+						IsProviderInScope (provider, entry.Provider, entry.Scope)) {
+						var clientElement =
+							ClientAutomationSource.Instance.GetOrCreateElement (provider);
+						var element = SourceManager.GetOrCreateAutomationElement (clientElement);
+						entry.Handler (element, e);
+					}
+		}
+
+		public static void RaiseAutomationPropertyChangedEvent (IRawElementProviderSimple provider,
+			AutomationPropertyChangedEventArgs e)
+		{
+			lock (propertyChangedEventEntries)
+				foreach (var entry in propertyChangedEventEntries)
+					if (IsProviderInScope (provider, entry.Provider, entry.Scope) &&
+						Array.Exists (entry.Properties, i => i == e.Property.Id)) {
+						var clientElement =
+							ClientAutomationSource.Instance.GetOrCreateElement (provider);
+						var element = SourceManager.GetOrCreateAutomationElement (clientElement);
+						// TODO implement
+						// Translate e.NewValue && e.OldValue
+						entry.Handler (element, e);
+					}
+		}
+
+		public static void RaiseStructureChangedEvent (IRawElementProviderSimple provider,
+			StructureChangedEventArgs e)
+		{
+			lock (structureChangedEventEntries)
+				foreach (var entry in structureChangedEventEntries)
+					if (IsProviderInScope (provider, entry.Provider, entry.Scope)) {
+						var clientElement =
+							ClientAutomationSource.Instance.GetOrCreateElement (provider);
+						var element = SourceManager.GetOrCreateAutomationElement (clientElement);
+						entry.Handler (element, e);
+					}
+		}
+
+		private static bool IsProviderInScope (IRawElementProviderSimple target,
+			IRawElementProviderSimple element, TreeScope scope)
+		{
+			if ((scope & TreeScope.Element) == TreeScope.Element && target == element)
+				return true;
+
+			IRawElementProviderFragment targetFragment = target as IRawElementProviderFragment;
+			IRawElementProviderFragment elementFragment = element as IRawElementProviderFragment;
+			if (targetFragment == null || elementFragment == null)
+				return false;
+
+			IRawElementProviderFragment targetFragmentRoot =
+				targetFragment.Navigate (NavigateDirection.Parent);
+			if ((scope & TreeScope.Children) == TreeScope.Children &&
+			    targetFragmentRoot != null &&
+			    targetFragmentRoot == elementFragment)
+				return true;
+			if ((scope & TreeScope.Descendants) == TreeScope.Descendants) {
+				while (targetFragmentRoot != null) {
+					if (targetFragmentRoot == elementFragment)
+						return true;
+					targetFragmentRoot = targetFragmentRoot.Navigate (NavigateDirection.Parent);
+				}
+			}
+
+			IRawElementProviderFragment elementFragmentRoot =
+				elementFragment.Navigate (NavigateDirection.Parent);
+			if ((scope & TreeScope.Parent) == TreeScope.Parent &&
+			    elementFragmentRoot != null &&
+			    elementFragmentRoot == targetFragment)
+				return true;
+			if ((scope & TreeScope.Ancestors) == TreeScope.Ancestors) {
+				while (elementFragmentRoot != null) {
+					if (elementFragmentRoot == targetFragment)
+						return true;
+					elementFragmentRoot = elementFragmentRoot.Navigate (NavigateDirection.Parent);
+				}
+			}
+
+			return false;
+		}
+#region Internal Classes
+
+		private class AutomationEventEntryBase
+		{
+			public AutomationEventEntryBase (IRawElementProviderSimple provider,
+			                                 TreeScope scope)
+			{
+				this.Provider = provider;
+				this.Scope = scope;
+			}
+
+			public IRawElementProviderSimple Provider { get; private set; }
+			public TreeScope Scope { get; private set; }
+		}
+
+		private class StructureChangedEventEntry : AutomationEventEntryBase
+		{
+			public StructureChangedEventEntry (IRawElementProviderSimple provider,
+			                                   TreeScope scope,
+			                                   StructureChangedEventHandler handler)
+				: base (provider, scope)
+			{
+				this.Handler = handler;
+			}
+			public StructureChangedEventHandler Handler { get; private set; }
+		}
+
+		private class AutomationEventEntry : AutomationEventEntryBase
+		{
+			public AutomationEventEntry (AutomationEvent eventId,
+			                             IRawElementProviderSimple provider,
+			                             TreeScope scope,
+			                             AutomationEventHandler handler)
+				: base (provider, scope)
+			{
+				this.EventId = eventId;
+				this.Handler = handler;
+			}
+
+			public AutomationEvent EventId { get; private set; }
+			public AutomationEventHandler Handler { get; private set; }
+		}
+
+		private class PropertyChangedEventEntry : AutomationEventEntryBase
+		{
+			public PropertyChangedEventEntry (IRawElementProviderSimple provider,
+			                                  TreeScope scope,
+			                                  int [] properties,
+			                                  AutomationPropertyChangedEventHandler handler)
+				: base (provider, scope)
+			{
+				this.Properties = properties;
+				this.Handler = handler;
+			}
+
+			public int [] Properties { get; private set; }
+			public AutomationPropertyChangedEventHandler Handler { get; private set; }
+		}
+#endregion
+	}
+}
Index: mono-uia.git/UIAutomationClient/Mono.UIAutomation.ClientSource/ClientInvokePattern.cs
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ mono-uia.git/UIAutomationClient/Mono.UIAutomation.ClientSource/ClientInvokePattern.cs	2012-01-23 18:58:44.780520283 +0000
@@ -0,0 +1,50 @@
+// Permission is hereby granted, free of charge, to any person obtaining 
+// a copy of this software and associated documentation files (the 
+// "Software"), to deal in the Software without restriction, including 
+// without limitation the rights to use, copy, modify, merge, publish, 
+// distribute, sublicense, and/or sell copies of the Software, and to 
+// permit persons to whom the Software is furnished to do so, subject to 
+// the following conditions: 
+//  
+// The above copyright notice and this permission notice shall be 
+// included in all copies or substantial portions of the Software. 
+//  
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
+// 
+// Copyright (c) 2010 Novell, Inc. (http://www.novell.com) 
+// 
+// Authors: 
+//     Matt Guo <matt@mattguo.com>
+// 
+
+using System;
+using System.Windows.Automation;
+using System.Windows.Automation.Provider;
+using Mono.UIAutomation.Source;
+
+namespace Mono.UIAutomation.ClientSource
+{
+	internal class ClientInvokePattern : IInvokePattern
+	{
+		private IInvokeProvider provider = null;
+
+		public ClientInvokePattern (IInvokeProvider provider)
+		{
+			this.provider = provider;
+		}
+
+		#region IInvokePattern implementation
+		public void Invoke ()
+		{
+			provider.Invoke ();
+		}
+
+		#endregion
+	}
+}
Index: mono-uia.git/UIAutomationClient/System.Windows.Automation/Automation.cs
===================================================================
--- mono-uia.git.orig/UIAutomationClient/System.Windows.Automation/Automation.cs	2011-03-06 12:25:27.000000000 +0000
+++ mono-uia.git/UIAutomationClient/System.Windows.Automation/Automation.cs	2012-01-23 18:58:44.780520283 +0000
@@ -28,6 +28,7 @@
 
 using AEIds = System.Windows.Automation.AutomationElementIdentifiers;
 using MUS = Mono.UIAutomation.Source;
+using Mono.UIAutomation.Services;
 
 namespace System.Windows.Automation
 {
@@ -309,14 +310,13 @@
 		                                       TreeScope scope,
 		                                       AutomationEventHandler eventHandler)
 		{
-			if (element == null)
-				throw new ArgumentNullException ("element");
-			if (eventHandler == null)
-				throw new ArgumentNullException ("eventHandler");
+			CheckAutomationEventId (eventId);
+			ArgumentCheck.NotNull (element, "element");
+			ArgumentCheck.NotNull (eventHandler, "eventHandler");
+
 			//TODO In theory we shall also check scope not equals to Parent or Ancestors,
 			//but .Net didn't test/throw exceptions for "scope"
 
-			CheckAutomationEventId (eventId.Id);
 			if (element == AutomationElement.RootElement)
 				foreach (var source in SourceManager.GetAutomationSources ())
 					source.AddAutomationEventHandler (
@@ -330,8 +330,7 @@
 
 		public static void AddAutomationFocusChangedEventHandler (AutomationFocusChangedEventHandler eventHandler)
 		{
-			if (eventHandler == null)
-				throw new ArgumentNullException ("eventHandler");
+			ArgumentCheck.NotNull (eventHandler, "eventHandler");
 
 			MUS.FocusChangedEventHandler sourceHandler;
 			//according to the spec, all static methods in the UIA lib shall be thread safe.
@@ -352,10 +351,8 @@
 		                                                      AutomationPropertyChangedEventHandler eventHandler,
 		                                                      params AutomationProperty [] properties)
 		{
-			if (element == null)
-				throw new ArgumentNullException ("element");
-			if (eventHandler == null)
-				throw new ArgumentNullException ("eventHandler");
+			ArgumentCheck.NotNull (element, "element");
+			ArgumentCheck.NotNull (eventHandler, "eventHandler");
 
 			if (element == AutomationElement.RootElement)
 				foreach (var source in SourceManager.GetAutomationSources ())
@@ -372,10 +369,8 @@
 		                                             TreeScope scope,
 		                                             StructureChangedEventHandler eventHandler)
 		{
-			if (element == null)
-				throw new ArgumentNullException ("element");
-			if (eventHandler == null)
-				throw new ArgumentNullException ("eventHandler");
+			ArgumentCheck.NotNull (element, "element");
+			ArgumentCheck.NotNull (eventHandler, "eventHandler");
 
 			if (element == AutomationElement.RootElement)
 				foreach (var source in SourceManager.GetAutomationSources ())
@@ -402,12 +397,9 @@
 			AutomationElement element,
 			AutomationEventHandler eventHandler)
 		{
-			if (element == null)
-				throw new ArgumentNullException ("element");
-			if (eventHandler == null)
-				throw new ArgumentNullException ("eventHandler");
-
-			CheckAutomationEventId (eventId.Id);
+			CheckAutomationEventId (eventId);
+			ArgumentCheck.NotNull (element, "element");
+			ArgumentCheck.NotNull (eventHandler, "eventHandler");
 
 			if (element == AutomationElement.RootElement)
 				foreach (var source in SourceManager.GetAutomationSources ())
@@ -421,8 +413,7 @@
 
 		public static void RemoveAutomationFocusChangedEventHandler (AutomationFocusChangedEventHandler eventHandler)
 		{
-			if (eventHandler == null)
-				throw new ArgumentNullException ("eventHandler");
+			ArgumentCheck.NotNull (eventHandler, "eventHandler");
 
 			MUS.FocusChangedEventHandler sourceHandler;
 			lock (focusHandlerMapping) {
@@ -437,10 +428,8 @@
 		public static void RemoveAutomationPropertyChangedEventHandler (
 			AutomationElement element, AutomationPropertyChangedEventHandler eventHandler)
 		{
-			if (element == null)
-				throw new ArgumentNullException ("element");
-			if (eventHandler == null)
-				throw new ArgumentNullException ("eventHandler");
+			ArgumentCheck.NotNull (element, "element");
+			ArgumentCheck.NotNull (eventHandler, "eventHandler");
 
 			if (element == AutomationElement.RootElement)
 				foreach (var source in SourceManager.GetAutomationSources ())
@@ -456,10 +445,8 @@
 		public static void RemoveStructureChangedEventHandler (
 			AutomationElement element, StructureChangedEventHandler eventHandler)
 		{
-			if (element == null)
-				throw new ArgumentNullException ("element");
-			if (eventHandler == null)
-				throw new ArgumentNullException ("eventHandler");
+			ArgumentCheck.NotNull (element, "element");
+			ArgumentCheck.NotNull (eventHandler, "eventHandler");
 
 			if (element == AutomationElement.RootElement)
 				foreach (var source in SourceManager.GetAutomationSources ())
@@ -472,12 +459,13 @@
 			}
 		}
 
-		private static void CheckAutomationEventId (int eventId)
+		private static void CheckAutomationEventId (AutomationEvent eventId)
 		{
-			if (AutomationElementIdentifiers.AutomationFocusChangedEvent.Id == eventId
-				|| AutomationElementIdentifiers.AutomationFocusChangedEvent.Id == eventId
-				|| AutomationElementIdentifiers.AutomationPropertyChangedEvent.Id == eventId
-				|| AutomationElementIdentifiers.StructureChangedEvent.Id == eventId)
+			ArgumentCheck.NotNull (eventId, "eventId");
+			if (AutomationElementIdentifiers.AutomationFocusChangedEvent == eventId
+				|| AutomationElementIdentifiers.AutomationFocusChangedEvent == eventId
+				|| AutomationElementIdentifiers.AutomationPropertyChangedEvent == eventId
+				|| AutomationElementIdentifiers.StructureChangedEvent == eventId)
 				throw new ArgumentException ("eventId");
 		}
 
Index: mono-uia.git/UIAutomationClient/System.Windows.Automation/AutomationElement.cs
===================================================================
--- mono-uia.git.orig/UIAutomationClient/System.Windows.Automation/AutomationElement.cs	2011-03-06 12:25:27.000000000 +0000
+++ mono-uia.git/UIAutomationClient/System.Windows.Automation/AutomationElement.cs	2012-01-23 18:58:44.780520283 +0000
@@ -523,8 +523,7 @@
 #region Public Static Methods
 		public static AutomationElement FromHandle (IntPtr hwnd)
 		{
-			if (hwnd == (IntPtr) null || hwnd == IntPtr.Zero)
-				throw new ArgumentException ("hwnd");
+			ArgumentCheck.Assert (hwnd, (h => h != IntPtr.Zero), "hwnd");
 			if (hwnd == NativeMethods.RootWindowHandle)
 				return RootElement;
 			AutomationElement element = null;
@@ -542,7 +541,9 @@
 
 		public static AutomationElement FromLocalProvider (IRawElementProviderSimple localImpl)
 		{
-			throw new NotImplementedException ();
+			IElement sourceElement = Mono.UIAutomation.ClientSource.ClientAutomationSource.Instance
+				.GetOrCreateElement (localImpl);
+			return new AutomationElement (sourceElement);
 		}
 
 		public static AutomationElement FromPoint (Point pt)
@@ -550,7 +551,12 @@
 			IntPtr handle = NativeMethods.WindowAtPosition ((int) pt.X, (int) pt.Y);
 			if (handle == IntPtr.Zero)
 				return RootElement;
-			AutomationElement startElement = FromHandle (handle);
+			AutomationElement startElement = null;
+			try {
+				startElement = FromHandle (handle);
+			} catch (ElementNotAvailableException) {
+				return RootElement;
+			}
 			if (startElement == RootElement)
 				return RootElement;
 			//Keep searching the descendant element which are not native window
Index: mono-uia.git/UIAutomationClient/System.Windows.Automation/ClientSettings.cs
===================================================================
--- mono-uia.git.orig/UIAutomationClient/System.Windows.Automation/ClientSettings.cs	2011-03-06 12:25:27.000000000 +0000
+++ mono-uia.git/UIAutomationClient/System.Windows.Automation/ClientSettings.cs	2012-01-23 18:58:44.780520283 +0000
@@ -26,6 +26,7 @@
 using System;
 using System.Reflection;
 using System.IO;
+using Mono.UIAutomation.Services;
 
 namespace System.Windows.Automation
 {
@@ -33,8 +34,7 @@
 	{
 		public static void RegisterClientSideProviderAssembly (AssemblyName assemblyName)
 		{
-			if (assemblyName == null)
-				throw new ArgumentNullException ("assemblyName");
+			ArgumentCheck.NotNull (assemblyName, "assemblyName");
 
 			Assembly assembly = null;
 			// TODO, wrap exception messages into Catalog.GetString
Index: mono-uia.git/UIAutomationClient/System.Windows.Automation/ClientSideProviderDescription.cs
===================================================================
--- mono-uia.git.orig/UIAutomationClient/System.Windows.Automation/ClientSideProviderDescription.cs	2011-03-06 12:25:27.000000000 +0000
+++ mono-uia.git/UIAutomationClient/System.Windows.Automation/ClientSideProviderDescription.cs	2012-01-23 18:58:44.780520283 +0000
@@ -64,5 +71,6 @@
 		DisallowBaseClassNameMatch
 	}
 
-	public delegate IRawElementProviderSimple ClientSideProviderFactoryCallback (IntPtr hwnd, int idChild, int idObject);
+	public delegate IRawElementProviderSimple ClientSideProviderFactoryCallback (
+		IntPtr hwnd, int idChild, int idObject);
 }
Index: mono-uia.git/UIAutomationClient/System.Windows.Automation/SourceManager.cs
===================================================================
--- mono-uia.git.orig/UIAutomationClient/System.Windows.Automation/SourceManager.cs	2011-03-06 12:25:27.000000000 +0000
+++ mono-uia.git/UIAutomationClient/System.Windows.Automation/SourceManager.cs	2012-01-23 18:58:44.780520283 +0000
@@ -29,6 +29,7 @@
 
 using Mono.UIAutomation.Source;
 using Mono.UIAutomation.Services;
+using Mono.UIAutomation.ClientSource;
 
 namespace System.Windows.Automation
 {
@@ -63,6 +64,7 @@
 							if (source != null)
 								sourcesList.Add (source);
 						}
+						sourcesList.Add (ClientAutomationSource.Instance);
 						sources = sourcesList.ToArray ();
 					}
 				}
Index: mono-uia.git/UIAutomationClientTests/UIAutomationClientTests/BaseTest.cs
===================================================================
--- mono-uia.git.orig/UIAutomationClientTests/UIAutomationClientTests/BaseTest.cs	2011-03-06 12:25:27.000000000 +0000
+++ mono-uia.git/UIAutomationClientTests/UIAutomationClientTests/BaseTest.cs	2012-01-23 18:58:44.780520283 +0000
@@ -471,6 +471,8 @@
 
 		public static string PrintRuntimeId (int [] runtimeId)
 		{
+			if (runtimeId == null)
+				return "(null)";
 			StringBuilder sb = new StringBuilder();
 			sb.Append ("[");
 			foreach (int id in runtimeId)
Index: mono-uia.git/UIAutomationClientTests/UIAutomationClientTests/LocalProviderTest.cs
===================================================================
--- mono-uia.git.orig/UIAutomationClientTests/UIAutomationClientTests/LocalProviderTest.cs	2011-03-06 12:25:27.000000000 +0000
+++ mono-uia.git/UIAutomationClientTests/UIAutomationClientTests/LocalProviderTest.cs	2012-01-23 19:01:38.121289614 +0000
@@ -38,17 +38,27 @@
 	[TestFixture]
 	public class LocalProviderTest
 	{
+		const int FakeHandle = 12345;
+
+		private AutomationElement simple = null;
+		private AutomationElement simple2 = null;
 		private AutomationElement child = null;
 		private AutomationElement root = null;
+		private CustomProviderSimple simpleProvider =null;
+		private CustomProviderSimple simpleProvider2 =null;
 		private CustomProviderFragment childProvider =null;
 		private CustomProviderRoot rootProvider =null;
 
 		[TestFixtureSetUp]
 		public virtual void FixtureSetUp ()
 		{
+			simpleProvider = new CustomProviderSimple ();
+			simpleProvider2 = new CustomProviderSimple (FakeHandle);
 			childProvider = new CustomProviderFragment (null);
-			rootProvider = new CustomProviderRoot(childProvider);
+			rootProvider = new CustomProviderRoot (childProvider);
 			childProvider.Root = rootProvider;
+			simple = AutomationElement.FromLocalProvider (simpleProvider);
+			simple2 = AutomationElement.FromLocalProvider (simpleProvider2);
 			child = AutomationElement.FromLocalProvider(childProvider);
 			root = AutomationElement.FromLocalProvider(rootProvider);
 		}
@@ -57,12 +67,93 @@
 		[Test]
 		public void PropertyTest ()
 		{
-			Assert.AreEqual ("Custom Simple", child.Current.Name);
+			Assert.AreEqual ("Custom Child", child.Current.Name);
 			Assert.AreEqual (ControlType.TabItem, child.Current.ControlType);
 			Assert.AreEqual ("Custom Root", root.Current.Name);
 			Assert.AreEqual (ControlType.Tab, root.Current.ControlType);
 		}
 
+		// IRawElementFragment's GetRuntimeId method will override
+		// the value returned by GetPropertyValue
+		[Test]
+		public void RuntimeIdOverrideTest ()
+		{
+			var rid1 = root.GetRuntimeId ();
+			var rid2 = (int []) root.GetCurrentPropertyValue (AEIds.RuntimeIdProperty);
+			Assert.AreEqual (rid1, rid2, "rid1 == rid2");
+			Assert.AreEqual (CustomProviderBase.CustomRuntimeIdPrefix, rid1 [0], "Check rid1");
+			Assert.AreEqual (CustomProviderBase.CustomRuntimeIdPrefix, rid2 [0], "Check rid2");
+
+			// RuntimeId is null even if it is explicitly returned by
+			// IRawElementSimple.GetPropertyValue
+			Assert.IsNull (simple.GetRuntimeId (), "simple.GetRuntimeId ()" );
+			Assert.IsNull (simple.GetCurrentPropertyValue (AEIds.RuntimeIdProperty),
+			               "simple.GetGetCurrentPropertyValue (RuntimeId)" );
+
+			// However if the IRawElementSimple has NativeHandleProperty,
+			// then UIA will generate a runtime id for the provider,
+			// on Windows 7 the runtime id is [42, NativeHandleValue]
+			Assert.IsNotNull (simple2.GetRuntimeId (), "simple2.GetRuntimeId ()" );
+		}
+
+		// IRawElementFragment's BoundingRectangle property will override
+		// the value returned by GetPropertyValue
+		[Test]
+		public void BoundingRectangleOverrideTest ()
+		{
+			var bound = root.Current.BoundingRectangle;
+			Assert.AreEqual (200.0, bound.Width, "bound.Width");
+
+			// BoundingRectangle is empty even if it is explicitly returned by
+			// IRawElementSimple.GetPropertyValue
+			Assert.IsTrue (simple.Current.BoundingRectangle.IsEmpty);
+		}
+
+		[Test]
+		public void DefaultPropertyValueTest ()
+		{
+			// LocalizedControlType is compatible with the ControlType though
+			// LocalizedControlType is not explicitly returned by ControlType
+			Assert.AreEqual (ControlType.Tab.LocalizedControlType, root.Current.LocalizedControlType,
+				"root.LocalizedControlType");
+			// IsInvokePatternAvailableProperty is automatically set to true as long as
+			// the pattern can be returned by GetPatternProvider
+			Assert.IsTrue ((bool) child.GetCurrentPropertyValue (AEIds.IsInvokePatternAvailableProperty),
+				"child.IsInvokePatternAvailable");
+			Assert.IsFalse ((bool) root.GetCurrentPropertyValue (AEIds.IsInvokePatternAvailableProperty),
+				"root.IsInvokePatternAvailable");
+		}
+
+		[Test]
+		public void FromPointTest ()
+		{
+			var element = AutomationElement.FromPoint (new SW.Point (100, 100));
+			// though child and root defined their bounds, they won't be returned by
+			// AutomationElement.FromPoint, actually on Windows what returned is the
+			// "Desktop" element.
+			Assert.AreNotEqual (element, child, "child is never returned by FromPoint");
+			Assert.AreNotEqual (element, root, "root is never returned by FromPoint");
+		}
+
+		[Test]
+		public void FromHandleTest ()
+		{
+			BaseTest.AssertRaises <ElementNotAvailableException> (
+				() =>  AutomationElement.FromHandle (new IntPtr (FakeHandle)),
+				"simple2 is never returned by FromHandle");
+		}
+
+		[Test]
+		public void FocusedElementTest ()
+		{
+			BaseTest.AssertRaises <InvalidOperationException> (
+				() => child.SetFocus (), "child.IsKeyboardFocusable is not set");
+			// root.IsKeyboardFocusable is set to ture, so no exception
+			root.SetFocus ();
+			Assert.AreNotEqual (AutomationElement.FocusedElement, root,
+				"root is never returned by FocusedElement");
+		}
+
 		[Test]
 		public void PatternTest ()
 		{
@@ -112,10 +203,58 @@
 		#endregion
 	}
 
+	internal class CustomProviderSimple : IRawElementProviderSimple
+	{
+		private int handle = -1;
+
+		public CustomProviderSimple ()
+		{
+		}
+
+		public CustomProviderSimple (int handle)
+		{
+			this.handle = handle;
+		}
+
+		#region IRawElementProviderSimple Members
+
+		public virtual object GetPatternProvider (int patternId)
+		{
+			return null;
+		}
+
+		public virtual object GetPropertyValue (int propertyId)
+		{
+			if (propertyId == AEIds.NameProperty.Id)
+				return "Custom Simple";
+			if (propertyId == AEIds.ControlTypeProperty.Id)
+				return ControlType.Pane.Id;
+			else if (propertyId == AEIds.RuntimeIdProperty.Id)
+				return new int[] {1, 2, 3, 4, 5};
+			else if (propertyId == AEIds.BoundingRectangleProperty.Id)
+				return new SW.Rect (0, 0, 1000, 1000);
+			else if (propertyId == AEIds.NativeWindowHandleProperty.Id && handle != -1)
+				return handle;
+			else
+				return null;
+		}
+
+		public IRawElementProviderSimple HostRawElementProvider {
+			get { return null; }
+		}
+
+		public ProviderOptions ProviderOptions {
+			get { return ProviderOptions.ClientSideProvider; }
+		}
+
+		#endregion
+	}
+
 	internal class CustomProviderBase : IRawElementProviderFragment
 	{
+		public const int CustomRuntimeIdPrefix = 8888;
 		private int[] runtimeId = null;
-		private SW.Rect rect = new SW.Rect (100.0, 100.0, 200.0, 200.0);
+		private SW.Rect bound = new SW.Rect (50.0, 50.0, 200.0, 200.0);
 
 		public CustomProviderBase (IRawElementProviderFragmentRoot root)
 		{
@@ -127,7 +266,7 @@
 		#region IRawElementProviderFragment Members
 
 		public SW.Rect BoundingRectangle {
-			get { return rect; }
+			get { return bound; }
 		}
 
 		public IRawElementProviderFragmentRoot FragmentRoot {
@@ -139,13 +278,12 @@
 			return new IRawElementProviderSimple[0];
 		}
 
-		public int [] GetRuntimeId ()
+		public int[] GetRuntimeId ()
 		{
-			const int CustomPrefix = 8888;
 			if (runtimeId == null) {
-				byte [] bytes = new Guid ().ToByteArray ();
+				byte [] bytes = Guid.NewGuid ().ToByteArray ();
 				runtimeId = new int [bytes.Length + 1];
-				runtimeId [0] = CustomPrefix;
+				runtimeId [0] = CustomRuntimeIdPrefix;
 				for (int i = 0; i < bytes.Length; i++)
 					runtimeId [i + 1] = bytes [i];
 			}
@@ -198,11 +336,10 @@
 		}
 
 		public int ClickCount { get; set; }
-
-		public void PerformInvoke ()
+		public void PerformInvoke()
 		{
 			ClickCount++;
-			AutomationInteropProvider.RaiseAutomationEvent(InvokePattern.InvokedEvent, this,
+			AutomationInteropProvider.RaiseAutomationEvent (InvokePattern.InvokedEvent, this,
 				new AutomationEventArgs(InvokePattern.InvokedEvent));
 		}
 
@@ -216,7 +353,7 @@
 		public override object GetPropertyValue (int propertyId)
 		{
 			if (propertyId == AEIds.NameProperty.Id)
-				return "Custom Simple";
+				return "Custom Child";
 			else if (propertyId == AEIds.ControlTypeProperty.Id)
 				return ControlType.TabItem.Id;
 			else
@@ -283,6 +420,14 @@
 				return "Custom Root";
 			else if (propertyId == AEIds.ControlTypeProperty.Id)
 				return ControlType.Tab.Id;
+			else if (propertyId == AEIds.RuntimeIdProperty.Id)
+				// this return value won't be effective since the base class defined GetRuntimeId method
+				return new int[] {1, 2, 3, 4, 5};
+			else if (propertyId == AEIds.BoundingRectangleProperty.Id)
+				// this return value won't be effective since the base class defined BoundingRectangle property
+				return new SW.Rect (0, 0, 1000, 1000);
+			else if (propertyId == AEIds.IsKeyboardFocusableProperty.Id)
+				return true;
 			else
 				return base.GetPropertyValue (propertyId);
 		}
Index: mono-uia.git/UIAutomationProvider/System.Windows.Automation.Provider/AutomationInteropProvider.cs
===================================================================
--- mono-uia.git.orig/UIAutomationProvider/System.Windows.Automation.Provider/AutomationInteropProvider.cs	2011-03-06 12:25:27.000000000 +0000
+++ mono-uia.git/UIAutomationProvider/System.Windows.Automation.Provider/AutomationInteropProvider.cs	2012-01-23 18:58:44.784520301 +0000
@@ -123,11 +123,13 @@
 			"UiaAtkBridge, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f4ceacb585d99812";
 		private static string UiaDbusBridgeAssembly =
 			"UiaDbusBridge, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f4ceacb585d99812";
+		private static string clientBridgeAssembly =
+			"UIAutomationClient, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
 
 		public static IList<IAutomationBridge> GetAutomationBridges ()
 		{
 			List<IAutomationBridge> bridges = new List<IAutomationBridge> ();
-			
+
 			// Let MONO_UIA_BRIDGE env var override default bridge
 			string bridgeAssemblyNames =
 				Environment.GetEnvironmentVariable ("MONO_UIA_BRIDGE");
@@ -135,7 +137,8 @@
 			if (string.IsNullOrEmpty (bridgeAssemblyNames))
 				bridgeAssemblyNames =
 					UiaAtkBridgeAssembly + ";" + UiaDbusBridgeAssembly;
-			
+			bridgeAssemblyNames += ";" + clientBridgeAssembly;
+
 			foreach (string bridgeAssembly in bridgeAssemblyNames.Split (';')) {
 				if (string.IsNullOrEmpty (bridgeAssembly))
 					continue;
Index: mono-uia.git/UIAutomationTypes/System.Windows.Automation/AutomationIdentifier.cs
===================================================================
--- mono-uia.git.orig/UIAutomationTypes/System.Windows.Automation/AutomationIdentifier.cs	2011-03-06 12:25:27.000000000 +0000
+++ mono-uia.git/UIAutomationTypes/System.Windows.Automation/AutomationIdentifier.cs	2012-01-23 18:58:44.784520301 +0000
@@ -57,10 +57,14 @@
 
 		public int CompareTo (object obj)
 		{
+			if (obj == null)
+				throw new ArgumentNullException ("obj");
 			AutomationIdentifier other =
 				obj as AutomationIdentifier;
 			if (other == null)
-				return 1; // TODO: What?
+				// As tested on Windows, when the object is not an AutomationIdentifier,
+				// a strange large integer will be returned, so we just return the MaxValue.
+				return int.MaxValue;
 			return id.CompareTo (other.Id);
 		}
 		
openSUSE Build Service is sponsored by