diff --git a/App.config b/App.config
index 8e15646..3062bfd 100644
--- a/App.config
+++ b/App.config
@@ -1,6 +1,24 @@
+
+
+
+
+
+
+
+
+ 3
+
+
+ 00:00:02
+
+
+
+
+
+
\ No newline at end of file
diff --git a/App.xaml.cs b/App.xaml.cs
index 33cc881..e755a39 100644
--- a/App.xaml.cs
+++ b/App.xaml.cs
@@ -1,17 +1,23 @@
-using System;
-using System.Collections.Generic;
-using System.Configuration;
-using System.Data;
-using System.Linq;
-using System.Threading.Tasks;
-using System.Windows;
+using System.Windows;
namespace ProcessCpuUsageStatusWindow
{
- ///
- /// Interaction logic for App.xaml
- ///
- public partial class App : Application
+ public partial class App
{
+ private WindowSource _windowSource;
+
+ protected override void OnStartup(StartupEventArgs e)
+ {
+ base.OnStartup(e);
+
+ _windowSource = new WindowSource();
+ }
+
+ protected override void OnExit(ExitEventArgs e)
+ {
+ _windowSource.Dispose();
+
+ base.OnExit(e);
+ }
}
}
diff --git a/ProcessCpuUsage.cs b/ProcessCpuUsage.cs
new file mode 100644
index 0000000..ba7d664
--- /dev/null
+++ b/ProcessCpuUsage.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Diagnostics;
+
+namespace ProcessCpuUsageStatusWindow
+{
+ public class ProcessCpuUsage
+ {
+ #region Properties
+
+ public string ProcessName { get; private set; }
+ public float PercentUsage { get; internal set; }
+ public DateTime LastFound { get; set; }
+ public bool UsageValid { get; private set; }
+
+ internal CounterSample LastSample { get; set; }
+
+ #endregion
+
+ #region Constructor
+
+ internal ProcessCpuUsage(InstanceData instanceData)
+ : this(instanceData, DateTime.MinValue)
+ { }
+
+ internal ProcessCpuUsage(InstanceData instanceData, DateTime timestamp)
+ {
+ // Store the process details
+ ProcessName = instanceData.InstanceName;
+
+ // Store the initial data
+ LastFound = timestamp;
+ LastSample = instanceData.Sample;
+
+ // We start out as not valid
+ UsageValid = false;
+ }
+
+ #endregion
+
+ #region Usage update
+
+ internal void UpdateCpuUsage(InstanceData instanceData, DateTime timestamp)
+ {
+ // Get the new sample
+ var newSample = instanceData.Sample;
+
+ // Calculate percent usage
+ PercentUsage = CounterSample.Calculate(LastSample, newSample) / Environment.ProcessorCount;
+
+ // Update the last sample and timestmap
+ LastSample = newSample;
+ LastFound = timestamp;
+
+ // Usage is now valid
+ UsageValid = true;
+ }
+
+ #endregion
+ }
+}
diff --git a/ProcessCpuUsageStatusWindow.csproj b/ProcessCpuUsageStatusWindow.csproj
index 2e6de5d..56e11c8 100644
--- a/ProcessCpuUsageStatusWindow.csproj
+++ b/ProcessCpuUsageStatusWindow.csproj
@@ -34,13 +34,13 @@
4
+
+ ..\FloatingStatusWindowLibrary\FloatingStatusWindowLibrary\bin\Debug\FloatingStatusWindowLibrary.dll
+
-
+
-
-
-
4.0
@@ -57,8 +57,11 @@
App.xaml
Code
+
+
+
Code
@@ -85,6 +88,9 @@
+
+
+
+
@@ -68,9 +69,10 @@
-
+
+
@@ -85,9 +87,10 @@
-
+
+
@@ -109,9 +112,25 @@
2.0
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ ..\Resources\ApplicationIcon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ CPU: {0,4:f1}% - Total
+
+
+
+
+
+ Loading...
+
+
+ CPU: {1,4:f1}% - {0}
+
\ No newline at end of file
diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs
index 5eeb11c..6e0bde0 100644
--- a/Properties/Settings.Designer.cs
+++ b/Properties/Settings.Designer.cs
@@ -8,23 +8,55 @@
//
//------------------------------------------------------------------------------
-namespace ProcessCpuUsageStatusWindow.Properties
-{
-
-
+namespace ProcessCpuUsageStatusWindow.Properties {
+
+
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
- internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
- {
-
- private static Settings defaultInstance = ((Settings) (global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
-
- public static Settings Default
- {
- get
- {
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
return defaultInstance;
}
}
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("3")]
+ public int ProcessCount {
+ get {
+ return ((int)(this["ProcessCount"]));
+ }
+ set {
+ this["ProcessCount"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("00:00:02")]
+ public global::System.TimeSpan UpdateInterval {
+ get {
+ return ((global::System.TimeSpan)(this["UpdateInterval"]));
+ }
+ set {
+ this["UpdateInterval"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("")]
+ public string WindowSettings {
+ get {
+ return ((string)(this["WindowSettings"]));
+ }
+ set {
+ this["WindowSettings"] = value;
+ }
+ }
}
}
diff --git a/Properties/Settings.settings b/Properties/Settings.settings
index 033d7a5..af8bde6 100644
--- a/Properties/Settings.settings
+++ b/Properties/Settings.settings
@@ -1,7 +1,15 @@
-
-
-
-
-
+
+
+
+
+ 3
+
+
+ 00:00:02
+
+
+
+
+
\ No newline at end of file
diff --git a/Resources/ApplicationIcon.ico b/Resources/ApplicationIcon.ico
new file mode 100644
index 0000000..20d66eb
Binary files /dev/null and b/Resources/ApplicationIcon.ico differ
diff --git a/WindowSource.cs b/WindowSource.cs
new file mode 100644
index 0000000..e2137dd
--- /dev/null
+++ b/WindowSource.cs
@@ -0,0 +1,113 @@
+using FloatingStatusWindowLibrary;
+using ProcessCpuUsageStatusWindow.Properties;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace ProcessCpuUsageStatusWindow
+{
+ public class WindowSource : IWindowSource, IDisposable
+ {
+ private readonly FloatingStatusWindow _floatingStatusWindow;
+ private readonly ProcessCpuUsageWatcher _processCpuUsageWatcher;
+
+ internal WindowSource()
+ {
+ _floatingStatusWindow = new FloatingStatusWindow(this);
+ _floatingStatusWindow.SetText(Resources.Loading);
+
+ _processCpuUsageWatcher = new ProcessCpuUsageWatcher();
+ _processCpuUsageWatcher.Initialize(Settings.Default.UpdateInterval, UpdateDisplay);
+ }
+
+ public void Dispose()
+ {
+ _processCpuUsageWatcher.Terminate();
+
+ _floatingStatusWindow.Save();
+ _floatingStatusWindow.Dispose();
+ }
+
+ public string Name
+ {
+ get { return "Process CPU Usage"; }
+ }
+
+ public System.Drawing.Icon Icon
+ {
+ get { return Resources.ApplicationIcon; }
+ }
+
+ public string WindowSettings
+ {
+ get
+ {
+ return Settings.Default.WindowSettings;
+ }
+ set
+ {
+ Settings.Default.WindowSettings = value;
+ Settings.Default.Save();
+ }
+ }
+
+ #region Display updating
+
+ private static class PredefinedProcessName
+ {
+ public const string Total = "_Total";
+ public const string Idle = "Idle";
+ }
+
+ private void UpdateDisplay(Dictionary currentProcessList)
+ {
+ // Filter the process list to valid ones and exclude the idle and total values
+ var validProcessList = (currentProcessList.Values.Where(
+ process =>
+ process.UsageValid && process.ProcessName != PredefinedProcessName.Total &&
+ process.ProcessName != PredefinedProcessName.Idle)).ToList();
+
+ // Calculate the total usage by adding up all the processes we know about
+ var totalUsage = validProcessList.Sum(process => process.PercentUsage);
+
+ // Sort the process list by usage and take only the top few
+ var sortedProcessList = (validProcessList.OrderByDescending(process => process.PercentUsage)).Take(Settings.Default.ProcessCount);
+
+ // Create a new string builder
+ var stringBuilder = new StringBuilder();
+
+ // Add the header line (if any)
+ if (Resources.HeaderLine.Length > 0)
+ {
+ stringBuilder.AppendFormat(Resources.HeaderLine, totalUsage);
+ stringBuilder.AppendLine();
+ stringBuilder.AppendLine();
+ }
+
+ // Loop over all processes in the sorted list
+ foreach (ProcessCpuUsage processCpuUsage in sortedProcessList)
+ {
+ // Move to the next line if it isn't the first line
+ if (stringBuilder.Length != 0)
+ stringBuilder.AppendLine();
+
+ // Format the process information into a string to display
+ stringBuilder.AppendFormat(Resources.ProcessLine, processCpuUsage.ProcessName, processCpuUsage.PercentUsage);
+ }
+
+ // Add the footer line (if any)
+ if (Resources.FooterLine.Length > 0)
+ {
+ stringBuilder.AppendLine();
+ stringBuilder.AppendLine();
+ stringBuilder.AppendFormat(Resources.FooterLine, totalUsage);
+ }
+
+ // Update the window with the text
+ _floatingStatusWindow.SetText(stringBuilder.ToString());
+ }
+
+ #endregion
+ }
+}