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

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

@ -44,7 +44,8 @@ namespace ICSharpCode.SharpDevelop @@ -44,7 +44,8 @@ namespace ICSharpCode.SharpDevelop
/// </summary>
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(IAddInTree), new AddInTreeImpl(null));
ServiceSingleton.ServiceProvider = container;

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

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

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

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

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

@ -38,7 +38,8 @@ namespace ICSharpCode.SharpDevelop.Sda @@ -38,7 +38,8 @@ namespace ICSharpCode.SharpDevelop.Sda
public void InitSharpDevelopCore(SharpDevelopHost.CallbackHelper callback, StartupSettings properties)
{
// 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(ILoggingService), new log4netLoggingService());
ServiceSingleton.ServiceProvider = container;

1
src/Main/SharpDevelop/SharpDevelop.csproj

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

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

@ -0,0 +1,38 @@ @@ -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 @@ -47,7 +47,6 @@ namespace ICSharpCode.SharpDevelop.Workbench
UILanguageService.ValidateLanguage();
SD.GetService<IOutputPad>(); // HACK: eagerly load output pad because pad services cannnot be instanciated from background threads
TaskService.Initialize();
Project.CustomToolsService.Initialize();
@ -55,6 +54,9 @@ namespace ICSharpCode.SharpDevelop.Workbench @@ -55,6 +54,9 @@ namespace ICSharpCode.SharpDevelop.Workbench
workbench.SetMemento(SD.PropertyService.NestedProperties(workbenchMemento));
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;
if (dlgMsgService != null) {
dlgMsgService.DialogSynchronizeInvoke = SD.MainThread.SynchronizingObject;

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

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

Loading…
Cancel
Save