Browse Source

When accessing a pad-service from the SD service container, the SD.MainThread.VerifyAccess() call is now performed on every GetService() call, not just on the first call.

pull/297/head
Daniel Grunwald 12 years ago
parent
commit
143332da32
  1. 1
      src/Main/Base/Project/ICSharpCode.SharpDevelop.addin
  2. 3
      src/Main/Base/Project/Services/SD.cs
  3. 15
      src/Main/Base/Project/Util/SharpDevelopServiceContainer.cs
  4. 7
      src/Main/Base/Project/Workbench/IOutputPad.cs
  5. 3
      src/Main/SharpDevelop/Sda/CallHelper.cs
  6. 1
      src/Main/SharpDevelop/SharpDevelop.csproj
  7. 38
      src/Main/SharpDevelop/Workbench/PadServiceProvider.cs
  8. 4
      src/Main/SharpDevelop/Workbench/WorkbenchStartup.cs
  9. 11
      src/Main/SharpDevelop/Workbench/WpfWorkbench.cs

1
src/Main/Base/Project/ICSharpCode.SharpDevelop.addin

@ -172,7 +172,6 @@
title = "${res:MainWindow.Windows.OutputWindow}" title = "${res:MainWindow.Windows.OutputWindow}"
icon = "PadIcons.Output" icon = "PadIcons.Output"
class = "ICSharpCode.SharpDevelop.Gui.CompilerMessageView" class = "ICSharpCode.SharpDevelop.Gui.CompilerMessageView"
serviceInterface = "ICSharpCode.SharpDevelop.Workbench.IOutputPad"
defaultPosition = "Bottom" /> defaultPosition = "Bottom" />
<Pad id = "PropertyPad" <Pad id = "PropertyPad"

3
src/Main/Base/Project/Services/SD.cs

@ -44,7 +44,8 @@ namespace ICSharpCode.SharpDevelop
/// </summary> /// </summary>
public static void InitializeForUnitTests() public static void InitializeForUnitTests()
{ {
var container = new SharpDevelopServiceContainer(ServiceSingleton.FallbackServiceProvider); var container = new SharpDevelopServiceContainer();
container.AddFallbackProvider(ServiceSingleton.FallbackServiceProvider);
container.AddService(typeof(IPropertyService), new PropertyServiceImpl()); container.AddService(typeof(IPropertyService), new PropertyServiceImpl());
container.AddService(typeof(IAddInTree), new AddInTreeImpl(null)); container.AddService(typeof(IAddInTree), new AddInTreeImpl(null));
ServiceSingleton.ServiceProvider = container; ServiceSingleton.ServiceProvider = container;

15
src/Main/Base/Project/Util/SharpDevelopServiceContainer.cs

@ -2,6 +2,7 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System; using System;
using System.Collections.Concurrent;
using System.ComponentModel.Design; using System.ComponentModel.Design;
using System.Linq; using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
@ -14,7 +15,7 @@ namespace ICSharpCode.SharpDevelop
/// </summary> /// </summary>
sealed class SharpDevelopServiceContainer : IServiceProvider, IServiceContainer, IDisposable sealed class SharpDevelopServiceContainer : IServiceProvider, IServiceContainer, IDisposable
{ {
readonly IServiceProvider parentProvider; readonly ConcurrentStack<IServiceProvider> fallbackProviders = new ConcurrentStack<IServiceProvider>();
readonly Dictionary<Type, object> services = new Dictionary<Type, object>(); readonly Dictionary<Type, object> services = new Dictionary<Type, object>();
readonly List<Type> servicesToDispose = new List<Type>(); readonly List<Type> servicesToDispose = new List<Type>();
readonly Dictionary<Type, object> taskCompletionSources = new Dictionary<Type, object>(); // object = TaskCompletionSource<T> for various T readonly Dictionary<Type, object> taskCompletionSources = new Dictionary<Type, object>(); // object = TaskCompletionSource<T> for various T
@ -25,9 +26,9 @@ namespace ICSharpCode.SharpDevelop
services.Add(typeof(IServiceContainer), this); services.Add(typeof(IServiceContainer), this);
} }
public SharpDevelopServiceContainer(IServiceProvider parentProvider) : this() public void AddFallbackProvider(IServiceProvider provider)
{ {
this.parentProvider = parentProvider; this.fallbackProviders.Push(provider);
} }
public object GetService(Type serviceType) public object GetService(Type serviceType)
@ -50,8 +51,12 @@ namespace ICSharpCode.SharpDevelop
} }
if (instance != null) if (instance != null)
return instance; return instance;
else foreach (var fallbackProvider in fallbackProviders) {
return parentProvider != null ? parentProvider.GetService(serviceType) : null; instance = fallbackProvider.GetService(serviceType);
if (instance != null)
return instance;
}
return null;
} }
public void Dispose() public void Dispose()

7
src/Main/Base/Project/Workbench/IOutputPad.cs

@ -3,6 +3,7 @@
using System; using System;
using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.Core;
namespace ICSharpCode.SharpDevelop.Workbench namespace ICSharpCode.SharpDevelop.Workbench
{ {
@ -10,6 +11,8 @@ namespace ICSharpCode.SharpDevelop.Workbench
/// The 'Output' pad. /// The 'Output' pad.
/// Allows showing a text log to the user. /// Allows showing a text log to the user.
/// </summary> /// </summary>
/// <remarks>This service is thread-safe.</remarks>
[SDService("SD.OutputPad")]
public interface IOutputPad public interface IOutputPad
{ {
/// <summary> /// <summary>
@ -39,6 +42,10 @@ namespace ICSharpCode.SharpDevelop.Workbench
IOutputCategory BuildCategory { get; } IOutputCategory BuildCategory { get; }
} }
/// <summary>
/// Represents a category in the <see cref="IOutputPad"/>.
/// </summary>
/// <remarks>This interface is thread-safe.</remarks>
public interface IOutputCategory public interface IOutputCategory
{ {
/// <summary> /// <summary>

3
src/Main/SharpDevelop/Sda/CallHelper.cs

@ -38,7 +38,8 @@ namespace ICSharpCode.SharpDevelop.Sda
public void InitSharpDevelopCore(SharpDevelopHost.CallbackHelper callback, StartupSettings properties) public void InitSharpDevelopCore(SharpDevelopHost.CallbackHelper callback, StartupSettings properties)
{ {
// Initialize the most important services: // Initialize the most important services:
var container = new SharpDevelopServiceContainer(ServiceSingleton.FallbackServiceProvider); var container = new SharpDevelopServiceContainer();
container.AddFallbackProvider(ServiceSingleton.FallbackServiceProvider);
container.AddService(typeof(IMessageService), new SDMessageService()); container.AddService(typeof(IMessageService), new SDMessageService());
container.AddService(typeof(ILoggingService), new log4netLoggingService()); container.AddService(typeof(ILoggingService), new log4netLoggingService());
ServiceSingleton.ServiceProvider = container; ServiceSingleton.ServiceProvider = container;

1
src/Main/SharpDevelop/SharpDevelop.csproj

@ -212,6 +212,7 @@
<Compile Include="Workbench\FullScreenEnabledWindow.cs" /> <Compile Include="Workbench\FullScreenEnabledWindow.cs" />
<Compile Include="Workbench\IWorkbenchLayout.cs" /> <Compile Include="Workbench\IWorkbenchLayout.cs" />
<Compile Include="Workbench\LayoutConfiguration.cs" /> <Compile Include="Workbench\LayoutConfiguration.cs" />
<Compile Include="Workbench\PadServiceProvider.cs" />
<Compile Include="Workbench\RecentOpen.cs" /> <Compile Include="Workbench\RecentOpen.cs" />
<Compile Include="Workbench\SDStatusBar.cs" /> <Compile Include="Workbench\SDStatusBar.cs" />
<Compile Include="Workbench\ShutdownService.cs" /> <Compile Include="Workbench\ShutdownService.cs" />

38
src/Main/SharpDevelop/Workbench/PadServiceProvider.cs

@ -0,0 +1,38 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
namespace ICSharpCode.SharpDevelop.Workbench
{
/// <summary>
/// A service provider that provides the pad services (as declared by the 'serviceInterface' attribute in the &lt;Pad&gt; codon).
/// </summary>
/// <remarks>
/// We register this as a fallback provider for the SD.Services container instead of directly registering the pads (using ServiceCreationCallback)
/// so that the thread-safety check in the .PadContent property accessor runs on every access to the service.
/// </remarks>
class PadServiceProvider : IServiceProvider
{
readonly List<PadDescriptor> pads = new List<PadDescriptor>();
public PadServiceProvider(IEnumerable<PadDescriptor> descriptors)
{
foreach (var descriptor in descriptors) {
if (descriptor.ServiceInterface != null) {
pads.Add(descriptor);
}
}
}
public object GetService(Type serviceType)
{
foreach (var pad in pads) {
if (serviceType == pad.ServiceInterface)
return pad.PadContent;
}
return null;
}
}
}

4
src/Main/SharpDevelop/Workbench/WorkbenchStartup.cs

@ -47,7 +47,6 @@ namespace ICSharpCode.SharpDevelop.Workbench
UILanguageService.ValidateLanguage(); UILanguageService.ValidateLanguage();
SD.GetService<IOutputPad>(); // HACK: eagerly load output pad because pad services cannnot be instanciated from background threads
TaskService.Initialize(); TaskService.Initialize();
Project.CustomToolsService.Initialize(); Project.CustomToolsService.Initialize();
@ -55,6 +54,9 @@ namespace ICSharpCode.SharpDevelop.Workbench
workbench.SetMemento(SD.PropertyService.NestedProperties(workbenchMemento)); workbench.SetMemento(SD.PropertyService.NestedProperties(workbenchMemento));
workbench.WorkbenchLayout = layout; workbench.WorkbenchLayout = layout;
// HACK: eagerly load output pad because pad services cannnot be instanciated from background threads
SD.Services.AddService(typeof(IOutputPad), CompilerMessageView.Instance);
var dlgMsgService = SD.MessageService as IDialogMessageService; var dlgMsgService = SD.MessageService as IDialogMessageService;
if (dlgMsgService != null) { if (dlgMsgService != null) {
dlgMsgService.DialogSynchronizeInvoke = SD.MainThread.SynchronizingObject; dlgMsgService.DialogSynchronizeInvoke = SD.MainThread.SynchronizingObject;

11
src/Main/SharpDevelop/Workbench/WpfWorkbench.cs

@ -105,10 +105,10 @@ namespace ICSharpCode.SharpDevelop.Workbench
{ {
UpdateFlowDirection(); UpdateFlowDirection();
foreach (PadDescriptor content in AddInTree.BuildItems<PadDescriptor>(viewContentPath, this, false)) { var padDescriptors = AddInTree.BuildItems<PadDescriptor>(viewContentPath, this, false);
if (content != null) { ((SharpDevelopServiceContainer)SD.Services).AddFallbackProvider(new PadServiceProvider(padDescriptors));
ShowPad(content); foreach (PadDescriptor content in padDescriptors) {
} ShowPad(content);
} }
mainMenu.ItemsSource = MenuService.CreateMenuItems(this, this, mainMenuPath, activationMethod: "MainMenu", immediatelyExpandMenuBuildersForShortcuts: true); mainMenu.ItemsSource = MenuService.CreateMenuItems(this, this, mainMenuPath, activationMethod: "MainMenu", immediatelyExpandMenuBuildersForShortcuts: true);
@ -432,9 +432,6 @@ namespace ICSharpCode.SharpDevelop.Workbench
throw new ArgumentException("Pad is already loaded"); throw new ArgumentException("Pad is already loaded");
padDescriptorCollection.Add(content); padDescriptorCollection.Add(content);
if (content.ServiceInterface != null) {
SD.Services.AddService(content.ServiceInterface, delegate { return content.PadContent; });
}
if (WorkbenchLayout != null) { if (WorkbenchLayout != null) {
WorkbenchLayout.ShowPad(content); WorkbenchLayout.ShowPad(content);

Loading…
Cancel
Save