Browse Source

Don't constantly create new threads to poll the clipboard.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@3892 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 17 years ago
parent
commit
7ec33b1bc5
  1. 1
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  2. 34
      src/Main/Base/Project/Src/TextEditor/ClipboardHandling.cs
  3. 105
      src/Main/Base/Project/Src/Util/WorkerThread.cs

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

@ -717,6 +717,7 @@ @@ -717,6 +717,7 @@
<Compile Include="Src\Util\GenericConverter.cs" />
<Compile Include="Src\Internal\Templates\TemplateLoadException.cs" />
<Compile Include="Src\Util\UnclosableStream.cs" />
<Compile Include="Src\Util\WorkerThread.cs" />
<EmbeddedResource Include="Resources\DefaultManifest.manifest" />
<EmbeddedResource Include="Src\Gui\Dialogs\ExtractInterfaceDialog.resx">
<DependentUpon>ExtractInterfaceDialog.cs</DependentUpon>

34
src/Main/Base/Project/Src/TextEditor/ClipboardHandling.cs

@ -5,9 +5,10 @@ @@ -5,9 +5,10 @@
// <version>$Revision$</version>
// </file>
using ICSharpCode.Core.WinForms;
using ICSharpCode.SharpDevelop.Util;
using System;
using System.Threading;
using ICSharpCode.Core.WinForms;
using ICSharpCode.SharpDevelop.Gui;
namespace ICSharpCode.SharpDevelop.DefaultEditor
@ -36,7 +37,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor @@ -36,7 +37,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor
UpdateClipboardContainsText();
}
static bool clipboardContainsText;
static volatile bool clipboardContainsText;
public static bool GetClipboardContainsText()
{
@ -47,28 +48,29 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor @@ -47,28 +48,29 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor
return clipboardContainsText;
}
static volatile Thread updateThread;
static WorkerThread workerThread;
static IAsyncResult currentWorker;
static void UpdateClipboardContainsText()
{
if (updateThread != null)
if (currentWorker != null && !currentWorker.IsCompleted)
return;
Thread t = new Thread(new ThreadStart(DoUpdate));
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Name = "clipboard access";
updateThread = t;
t.Start();
t.Join(50); // wait a few ms in case the clipboard can be accessed without problems
if (workerThread == null) {
workerThread = new WorkerThread();
Thread t = new Thread(new ThreadStart(workerThread.RunLoop));
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Name = "clipboard access";
t.Start();
}
currentWorker = workerThread.Enqueue(DoUpdate);
// wait a few ms in case the clipboard can be accessed without problems
currentWorker.AsyncWaitHandle.WaitOne(50);
}
static void DoUpdate()
{
try {
clipboardContainsText = ClipboardWrapper.ContainsText;
} finally {
updateThread = null;
}
clipboardContainsText = ClipboardWrapper.ContainsText;
}
}
}

105
src/Main/Base/Project/Src/Util/WorkerThread.cs

@ -0,0 +1,105 @@ @@ -0,0 +1,105 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <author name="Daniel Grunwald"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Threading;
namespace ICSharpCode.SharpDevelop.Util
{
/// <summary>
/// A worker thread that normally sleeps, but can run a queue of commands.
/// </summary>
public class WorkerThread
{
sealed class AsyncTask : IAsyncResult
{
internal readonly ManualResetEvent manualResetEvent = new ManualResetEvent(false);
internal readonly Action method;
volatile bool isCompleted;
internal AsyncTask(Action method)
{
this.method = method;
}
internal void SetCompleted()
{
isCompleted = true;
manualResetEvent.Set();
}
public bool IsCompleted {
get { return isCompleted; }
}
public WaitHandle AsyncWaitHandle {
get { return manualResetEvent; }
}
public object AsyncState { get; set; }
public bool CompletedSynchronously { get { return false; } }
}
/// <summary>
/// Runs <paramref name="method"/> on the worker thread.
/// </summary>
/// <param name="method">The method to run.</param>
/// <returns></returns>
public IAsyncResult Enqueue(Action method)
{
if (method == null)
throw new ArgumentNullException("method");
AsyncTask task = new AsyncTask(method);
lock (lockObject) {
taskQueue.Enqueue(task);
Monitor.Pulse(lockObject);
}
return task;
}
readonly object lockObject = new object();
Queue<AsyncTask> taskQueue = new Queue<AsyncTask>();
bool workerRunning = false;
/// <summary>
/// Runs the worker thread loop on the current thread.
/// </summary>
public void RunLoop()
{
lock (lockObject) {
if (workerRunning)
throw new InvalidOperationException("There already is a worker running");
workerRunning = true;
}
try {
while (workerRunning) {
AsyncTask task;
lock (lockObject) {
while (taskQueue.Count == 0)
Monitor.Wait(lockObject);
task = taskQueue.Dequeue();
}
task.method();
task.SetCompleted();
}
} finally {
lock (lockObject) {
workerRunning = false;
}
}
}
/// <summary>
/// Exits running the worker thread.
/// </summary>
public void ExitWorkerThread()
{
Enqueue(delegate { workerRunning = false; });
}
}
}
Loading…
Cancel
Save