Reintegrated 2.3 branch into trunk

This commit is contained in:
Birunthan Mohanathas
2012-01-08 17:35:29 +00:00
parent c3335adec5
commit c3ed2e5fa3
87 changed files with 5379 additions and 2732 deletions

View File

@ -0,0 +1,7 @@
using System.Reflection;
using System.Runtime.CompilerServices;
[assembly: AssemblyCopyright("© 2010 - Peter Souza IV")]
[assembly: AssemblyVersion("1.4.0.0")]
[assembly: AssemblyInformationalVersion(Rainmeter.Version.Informational)]
[assembly: AssemblyProduct("Rainmeter")]

View File

@ -0,0 +1,105 @@
namespace InputText
{
partial class InputBox
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.txtInput = new System.Windows.Forms.TextBox();
this.btnOK = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// txtInput
//
this.txtInput.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.txtInput.Location = new System.Drawing.Point(0, 0);
this.txtInput.Margin = new System.Windows.Forms.Padding(0);
this.txtInput.Multiline = true;
this.txtInput.Name = "txtInput";
this.txtInput.Size = new System.Drawing.Size(200, 22);
this.txtInput.TabIndex = 0;
this.txtInput.Leave += new System.EventHandler(this.txtInput_Leave);
//
// btnOK
//
this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK;
this.btnOK.Location = new System.Drawing.Point(2, 2);
this.btnOK.Margin = new System.Windows.Forms.Padding(0);
this.btnOK.Name = "btnOK";
this.btnOK.Size = new System.Drawing.Size(2, 2);
this.btnOK.TabIndex = 1;
this.btnOK.TabStop = false;
this.btnOK.Text = "OK";
this.btnOK.UseVisualStyleBackColor = true;
this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
//
// btnCancel
//
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnCancel.Location = new System.Drawing.Point(2, 2);
this.btnCancel.Margin = new System.Windows.Forms.Padding(0);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(2, 2);
this.btnCancel.TabIndex = 2;
this.btnCancel.TabStop = false;
this.btnCancel.Text = "btnCancel";
this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
//
// InputBox
//
this.AcceptButton = this.btnOK;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.AutoSize = true;
this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.CancelButton = this.btnCancel;
this.ClientSize = new System.Drawing.Size(251, 42);
this.Controls.Add(this.txtInput);
this.Controls.Add(this.btnCancel);
this.Controls.Add(this.btnOK);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Name = "InputBox";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "InputBox";
this.Deactivate += new System.EventHandler(this.InputBox_Deactivate);
this.Load += new System.EventHandler(this.InputBox_Load);
this.Shown += new System.EventHandler(this.InputBox_Shown);
this.Leave += new System.EventHandler(this.InputBox_Leave);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox txtInput;
private System.Windows.Forms.Button btnOK;
private System.Windows.Forms.Button btnCancel;
}
}

View File

@ -0,0 +1,323 @@
using System;
using System.Drawing;
using System.Windows.Forms;
namespace InputText
{
public partial class InputBox : Form
{
public Rainmeter.Settings.InstanceSettings Instance = null;
#region Default form initializer
public InputBox()
{
InitializeComponent();
}
#endregion
// This event will make sure we have focus when the inputbox is shown ot the user.
// it will only cause focus if the window itself has focus (i.e. doesn't steal).
private void InputBox_Shown(object sender, EventArgs e)
{
this.Activate();
this.BringToFront();
this.Activate();
this.BringToFront();
this.txtInput.Focus();
}
// All exceptions are swallowed for the sake of this example. Since the majority
// (if not all) of these are rather simple in nature, debugging without errors
// should be fairly simple anyway.
//
// However, if you wanted to log errors, a simple way would be to add something like
// this:
//
// try
// {
// ... // code you are testing
// }
// catch (Exception ex)
// {
// Rainmeter.Log(Rainmeter.LogLevel.Warning, "InputText :: exception :: " + ex.GetType().ToString() + ": " + ex.Message);
// }
#region TextInput -- returns the inputted text
public string TextInput
{
get
{
return this.txtInput.Text.Trim();
}
}
#endregion
#region ChangeFontFace(string) -- changes the text's font name
public void ChangeFontFace(string sFont)
{
try
{
this.txtInput.Font = new Font(sFont, this.txtInput.Font.Size);
}
catch { }
}
#endregion
#region ChangeFontColor(string) -- changes the font's color, supports 6 and 8-digit hex or a series of 3 or 4 comma-separated numbers
public void ChangeFontColor(string sColor)
{
try
{
sColor = sColor.Trim();
if (sColor.Contains(",")) // #,#,# or #,#,#,# format
{
string[] sParts = sColor.Trim().Replace(" ", string.Empty).Split(new char[] { ',' }, StringSplitOptions.None);
this.txtInput.ForeColor = Color.FromArgb(int.Parse(sParts[0]), int.Parse(sParts[1]), int.Parse(sParts[2]));
this.txtInput.ForeColor = Color.FromArgb(int.Parse(sParts[3]), int.Parse(sParts[0]), int.Parse(sParts[1]), int.Parse(sParts[2]));
}
else
{
if (sColor.Length == 6) // 6-digit hex (no alpha transparency)
{
uint iColor = uint.Parse(sColor, System.Globalization.NumberStyles.HexNumber);
// Since it was omitted, force full opacity (not transparent at all)
this.txtInput.ForeColor = Color.FromArgb((int)(0xFF000000 | iColor));
}
else if (sColor.Length == 8) // 8-digit hex (with alpha transparency)
{
uint iColor = uint.Parse(sColor, System.Globalization.NumberStyles.HexNumber);
// This swaps RRGGBBAA for AARRGGBB, which Color.FromArgb() wants
iColor = ((iColor & 0xFFFFFF00) >> 8) | ((iColor & 0x000000FF) << 24);
this.txtInput.ForeColor = Color.FromArgb((int)iColor);
}
}
}
catch { }
}
#endregion
#region ChangeBackColor(string) -- changes the background color, supports 6 and 8-digit hex or a series of 3 or 4 comma-separated numbers
public void ChangeBackColor(string sColor)
{
try
{
sColor = sColor.Trim();
if (sColor.Contains(",")) // #,#,# or #,#,#,# format
{
string[] sParts = sColor.Trim().Replace(" ", string.Empty).Split(new char[] { ',' }, StringSplitOptions.None);
this.txtInput.BackColor = Color.FromArgb(int.Parse(sParts[0]), int.Parse(sParts[1]), int.Parse(sParts[2]));
// Change 0-255 transparency to a 0.0-1.0 transparency range
double dTrans = (double)int.Parse(sParts[3]);
dTrans /= 255.0;
this.Opacity = dTrans;
}
else
{
if (sColor.Length == 6) // 6-digit hex (no alpha transparency)
{
uint iColor = uint.Parse(sColor, System.Globalization.NumberStyles.HexNumber);
this.txtInput.BackColor = Color.FromArgb((int)(0xFF000000 | iColor));
// Since it was omitted, force full opacity (not transparent at all)
this.Opacity = 1.0;
}
else if (sColor.Length == 8) // 8-digit hex (with alpha transparency)
{
uint iColor = uint.Parse(sColor, System.Globalization.NumberStyles.HexNumber);
// This swaps RRGGBBAA for AARRGGBB, which Color.FromArgb() wants
iColor = ((iColor & 0xFFFFFF00) >> 8) | ((iColor & 0x000000FF) << 24);
this.txtInput.BackColor = Color.FromArgb((int)((0xFF000000) | (0x00FFFFFF & iColor)));
// Change 0-255 transparency to a 0.0-1.0 transparency range
double dTrans = (double)((iColor & 0xFF000000) >> 24);
dTrans /= 255.0;
this.Opacity = dTrans;
}
}
}
catch { }
}
#endregion
#region ChangeStringAlign(string) -- Changes text horizontal alignment
public void ChangeStringAlign(string sAlign)
{
try
{
sAlign = sAlign.ToUpper().Trim();
if (sAlign == "LEFT")
this.txtInput.TextAlign = HorizontalAlignment.Left;
else if (sAlign == "CENTER")
this.txtInput.TextAlign = HorizontalAlignment.Center;
else if (sAlign == "RIGHT")
this.txtInput.TextAlign = HorizontalAlignment.Right;
}
catch { }
}
#endregion
#region ChangeFontSize(string) -- changes the font's point size (supports floating-point values)
public void ChangeFontSize(string sSize)
{
try
{
this.txtInput.Font = new Font(this.txtInput.Font.OriginalFontName, float.Parse(sSize));
}
catch { }
}
#endregion
#region MakeTopmost() -- forces the form to have the 'Always On Top' property
public void MakeTopmost()
{
this.TopMost = true;
}
#endregion
#region MakePassword() -- causes the textbox to be password style
public void MakePassword()
{
this.txtInput.PasswordChar = '*';
}
#endregion
#region ChangeFontStringStyle() -- changes the font's bold/italic styles
public void ChangeFontStringStyle(string sStyle)
{
try
{
sStyle = sStyle.ToUpper().Trim();
if (sStyle == "NORMAL")
this.txtInput.Font = new Font(this.txtInput.Font, FontStyle.Regular);
else if (sStyle == "BOLD")
this.txtInput.Font = new Font(this.txtInput.Font, FontStyle.Bold);
else if (sStyle == "ITALIC")
this.txtInput.Font = new Font(this.txtInput.Font, FontStyle.Italic);
else if (sStyle == "BOLDITALIC")
this.txtInput.Font = new Font(this.txtInput.Font, FontStyle.Bold | FontStyle.Italic);
}
catch { }
}
#endregion
#region ChangeW(string) -- changes the width of the input textbox
public void ChangeW(string sWidth)
{
try
{
this.txtInput.Width = int.Parse(sWidth);
}
catch { }
}
#endregion
#region ChangeH(string) -- changes the height of the input textbox
public void ChangeH(string sHeight)
{
try
{
this.txtInput.Height = int.Parse(sHeight);
}
catch { }
}
#endregion
#region ChangeX(string) -- changes the X (horizontal) position of the input textbox, relative to its parent skin
public void ChangeX(Rainmeter.Settings.InstanceSettings Instance, string sX)
{
try
{
// If the position is changed, make sure the form's auto-location is disabled.
if (this.StartPosition != FormStartPosition.Manual)
this.StartPosition = FormStartPosition.Manual;
// Notice that we need the position of the parent window for offset location.
//
// The Rainmeter class does this for us
this.Location = new System.Drawing.Point(Rainmeter.ConfigX(Rainmeter.SkinName(Instance)) + int.Parse(sX), this.Location.Y);
}
catch { }
}
#endregion
#region ChangeY(string) -- changes the Y (vertical) position of the input textbox, relative to its parent skin
public void ChangeY(Rainmeter.Settings.InstanceSettings Instance, string sY)
{
try
{
// If the position is changed, make sure the form's auto-location is disabled.
if (this.StartPosition != FormStartPosition.Manual)
this.StartPosition = FormStartPosition.Manual;
// Notice that we need the position of the parent window for offset location.
//
// The Rainmeter class does this for us
this.Location = new System.Drawing.Point(this.Location.X, Rainmeter.ConfigY(Rainmeter.SkinName(Instance)) + int.Parse(sY));
}
catch { }
}
#endregion
#region DefaultValue(string) -- sets the default text to appear in the input textbox
public void DefaultValue(string val)
{
this.txtInput.Text = val;
}
#endregion
#region MakeFocusDismiss(bool) -- dismisses the input textbox if it loses cursor/window focus
private bool _FocusDismiss = true;
public DialogResult drBackup = DialogResult.None;
public string sTextValue = string.Empty;
public void MakeFocusDismiss(bool bDismissing)
{
this._FocusDismiss = bDismissing;
}
private void txtInput_Leave(object sender, EventArgs e)
{
if (this._FocusDismiss)
{
this.drBackup = DialogResult.Cancel;
this.Close();
}
}
private void InputBox_Leave(object sender, EventArgs e)
{
if (this._FocusDismiss)
{
this.drBackup = DialogResult.Cancel;
this.Close();
}
}
private void InputBox_Deactivate(object sender, EventArgs e)
{
if (this._FocusDismiss)
{
this.drBackup = DialogResult.Cancel;
this.Close();
}
}
private void btnOK_Click(object sender, EventArgs e)
{
_FocusDismiss = false;
this.sTextValue = this.txtInput.Text.Trim();
this.drBackup = DialogResult.OK;
this.DialogResult = DialogResult.OK;
this.Close();
}
private void btnCancel_Click(object sender, EventArgs e)
{
_FocusDismiss = false;
this.drBackup = DialogResult.Cancel;
this.DialogResult = DialogResult.Cancel;
this.Close();
}
#endregion
private void InputBox_Load(object sender, EventArgs e)
{
this.Activate();
this.BringToFront();
this.Activate();
this.BringToFront();
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,173 @@
using System;
using Rainmeter;
namespace InputText
{
public class Main
{
/// <summary>
/// Your name (author) and the version of the plugin go here. The code will
/// automatically format the values and send them back when a call to GetAuthor()
/// or GetVersion() is made.
///
/// Optionally, you may also provide an e-mail address and additional comments
/// </summary>
private static Rainmeter.Settings Plugin = new Rainmeter.Settings
(
// Author name
"Peter Souza IV",
// Version
1.05,
// E-mail
"psouza4@gmail.com",
// Comments (try to keep it under 50 characters)
"Please visit the forums for support."
);
#region GetAuthor() and GetVersion() exports -- no need to modify
[DllExport]
public static UInt32 GetPluginVersion()
{
return Rainmeter.Version(Plugin.Version);
}
[DllExport]
public unsafe static char* GetPluginAuthor()
{
if (!string.IsNullOrEmpty(Plugin.Email) && !string.IsNullOrEmpty(Plugin.Comments))
return Rainmeter.String(Plugin.Author + " (" + Plugin.Email + "): " + Plugin.Comments);
if (!string.IsNullOrEmpty(Plugin.Email))
return Rainmeter.String(Plugin.Author + " (" + Plugin.Email + ")");
if (!string.IsNullOrEmpty(Plugin.Comments))
return Rainmeter.String(Plugin.Author + ": " + Plugin.Comments);
return Rainmeter.String(Plugin.Author);
}
#endregion
#region Initialize() and Finalize() -- you may add to these functions if necessary
[DllExport]
public unsafe static UInt32 Initialize(IntPtr instance, char* iniFile, char* section, UInt32 id)
{
Plugin.AddInstance(iniFile, section, id); // required: do not remove
////////////////////////////////////////////////////////////////
//
// You may add code here, if necessary
//
////////////////////////////////////////////////////////////////
return 0;
}
[DllExport]
public static void Finalize(IntPtr instance, UInt32 id)
{
Plugin.RemoveInstance(id); // required: do not remove
////////////////////////////////////////////////////////////////
//
// You may add code here, if necessary
//
////////////////////////////////////////////////////////////////
return;
}
#endregion
#region Update(), Update2(), and GetString() exports -- please read notes
// *** WARNING / NOTES ***
//
// Do not add to this code: change your code in PluginCode.cs instead
//
// However, due to the way Rainmeter works, you will probably want to
// comment-out either 'Update' or 'Update2' if your plugin will be returning
// numeric values.
//
// Rainmeter will look for 'Update' for positive integers. If you want to
// allow negative numbers or floating-point numbers, use 'Update2' instead.
//
// You *MUST* comment-out whichever function you don't want to use for this
// to work.
//
// If you don't care, such as a plugin that either doesn't return data or
// only returns string/text data, then you can leave them both here (it won't
// hurt anything).
//
// *** WARNING / NOTES ***
/// <summary>
/// Rainmeter's request for numeric data from the plugin. This version can only
/// return positive integers ranging from 0 to 4,294,967,296. Comment this member
/// out and use 'Update2' if you want to return negative or floating-point values.
/// </summary>
/// <param name="id">The unique instance ID of this request.</param>
/// <returns>Current value for this meter.</returns>
[DllExport]
public static UInt32 Update(UInt32 id)
{
// Do not modify this member (although you can comment it out). Instead, update
// your code in 'PluginCode.cs'.
return new YourPlugin().Update(Plugin, id);
}
/// <summary>
/// Rainmeter's request for numeric data from the plugin. This version can return
/// positive or negative floating-point numbers (32-bit precision). Comment this
/// member out and use 'Update' if you want to only return positive integers.
/// </summary>
/// <param name="id">The unique instance ID of this request.</param>
/// <returns>Current value for this meter.</returns>
[DllExport]
public static double Update2(UInt32 id)
{
// Do not modify this member (although you can comment it out). Instead, update
// your code in 'PluginCode.cs'.
return new YourPlugin().Update2(Plugin, id);
}
/// <summary>
/// Rainmeter's request for text data from the plugin.
/// </summary>
/// <param name="id">The unique instance ID of this request.</param>
/// <param name="flags">Unused still as of Dec 2nd, 2010.</param>
/// <returns></returns>
[DllExport]
public unsafe static char* GetString(UInt32 id, UInt32 flags)
{
// Do not modify this member. Instead, update your code in 'PluginCode.cs'.
return Rainmeter.String(new YourPlugin().GetString(Plugin, id));
}
#endregion
#region ExecuteBang() export -- no need to modify (change code in PluginCode.cs)
[DllExport]
public static unsafe void ExecuteBang(char* args, UInt32 id)
{
new YourPlugin().ExecuteBang(Plugin, id, new string(args));
return;
}
#endregion
}
/// <summary>
/// Dummy attribute to mark method as exported for DllExporter.exe.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class DllExport : Attribute
{
public DllExport()
{
}
}
}

View File

@ -0,0 +1,476 @@
using System;
using System.Collections.Generic;
// The bulk of your plugin's code belongs in this file.
namespace InputText
{
class PluginCode
{
// 'Update', 'Update2', and 'GetString' all return data back to Rainmeter, depending on
// if the Rainmeter measure wants a numeric value or a string/text data.
//
// The 'Instance' member contains all of the data necessary to read the INI file
// passed to your plugin when this instance was first initialized. Remember: your plugin
// may be initialized multiple times. For example, a plugin that reads the free space
// of a hard drive may be called multiple times -- once for each installed hard drive.
public UInt32 Update(Rainmeter.Settings.InstanceSettings Instance)
{
return 0;
}
public double Update2(Rainmeter.Settings.InstanceSettings Instance)
{
return 0.0;
}
public string GetString(Rainmeter.Settings.InstanceSettings Instance)
{
// This plugin is unique as it is one of the first to not be used to display data
// back in Rainmeter, but to request user input and use that input during batch
// operations (and other purposes).
//
// However, Rainmeter requires that data be sent back, so we'll return temporary data
// In this case, the data is whatever the user last entered into an input textbox.
return Instance.GetTempValue("LastInput", string.Empty).ToString();
}
// 'ExecuteBang' is a way of Rainmeter telling your plugin to do something *right now*.
// What it wants to do can be defined by the 'Command' parameter.
public void ExecuteBang(Rainmeter.Settings.InstanceSettings Instance, string Command)
{
#region Handle a single parameter
// If our parameter list only contains a single word, then open a textbox immediately
// and set a value. This mode does not do any batching.
if (!Command.Trim().Contains(" "))
{
// Assume that the parameter is the name of the variable
string sVariableName = Command.Trim();
// Ask for input
string sInput = GetUserInput(Instance);
// If the user cancelled out of the inputbox (ESC key, etc.), then abort
if (sInput == null)
return;
// Ask Rainmeter to set the variable using a bang (http://rainmeter.net/RainCMS/?q=Bangs)
Rainmeter.Bang("!RainmeterSetVariable " + sVariableName + " \"" + sInput.Replace("\"", "\\\"") + "\"");
// Note that the skin needs DynamicVariables=1 in the measure's settings or the above
// code will have no effect.
return;
}
#endregion
#region Handle multiple parameters
// Our parameter list contains at least two words, so split them up
string[] sParts = Command.Trim().Split(new string[] { " " }, StringSplitOptions.None);
// If the first parameter is 'ExecuteBatch' (not case sensitive)...
if (sParts[0].Trim().ToUpper() == "EXECUTEBATCH")
{
// ExecuteBatch tells this plugin to go through the measure's settings to look
// for lines beginning with "Command" and executing Rainmeter bangs for each one.
// If a line contains $UserInput$, then an input textbox is opened and command
// execution pauses until the user enters text or dismisses the textbox. If the
// textbox is dismissed (Escape key, for example), all processing ends, otherwise
// it continues depending on the range of commands selected.
//
// Each "Command" line allows overriding all settings that the input textbox
// supports, therefor some checking and substitution is performed, thus a
// more complex parser has been implemented.
//
// ExecuteBatch expects this syntax:
// ExecuteBatch [All|#|#-#]
//
// This allows Rainmeter to call the plugin to execute a range including:
// All All commands in the measure
// # Only a single command in the measure
// #-# A specific range of commands in the measure
#region Determine range
// Determine range. Default is 1 to 1,000,000,000, although if processing finds
// that a requested line is blank, it will stop all processing (so 'All' will
// only parse 14 lines if "Command15" does not exist or is blank).
int iMin = 1;
int iMax = 1000000000;
try
{
if (sParts[1].Trim().ToUpper() != "ALL")
{
if (sParts[1].Contains("-"))
{
string[] sSubParts = sParts[1].Split(new string[] { "-" }, StringSplitOptions.None);
iMin = int.Parse(sSubParts[0]);
iMax = int.Parse(sSubParts[1]);
}
else
iMin = iMax = int.Parse(sParts[1]);
}
}
catch // handle all errors above
{
// Any error above will be ignored and the default range used instead.
// This can occur if the measure asks to ExecuteBatch an invalid range
// or the range could not be translated to an acceptable format.
//
// For example: ExecuteBatch asdf
iMin = 1;
iMax = 1000000000;
}
#endregion
#region Parse commands in range
// Parse each command in the range, aborting if any line returns 'false' or
// the requested command line does not exist in the config for that measure.
for (int i = iMin; i <= iMax; i++)
{
// Read this command's line
string sCurrentLine = Instance.INI_Value("Command" + i.ToString());
// If empty/non-existent, abort
if (string.IsNullOrEmpty(sCurrentLine))
break;
// Execute the line, but if there's a problem (error or they cancel the
// input textbox), then abort
if (!ExecuteLine(Instance, sCurrentLine))
break;
// Continue to the next line, if there is any
}
#endregion
return;
}
// Unhandled command, log the message but otherwise do nothing
Rainmeter.Log(Rainmeter.LogLevel.Debug, "InputText: Received command \"" + sParts[0].Trim() + "\", left unhandled");
#endregion
return;
}
#region This is all code custom to this plugin
#region Parse the current command line
private bool ExecuteLine(Rainmeter.Settings.InstanceSettings Instance, string sLine)
{
// If this line contains a $UserInput$ token, then we need to do some extra
// parsing
if (sLine.ToUpper().Contains("$USERINPUT$"))
{
try
{
#region Handle in-line overrides
// Create a blank list of overrides
Dictionary<string, string> Overrides = new Dictionary<string, string>();
// Start looking for overridable settings and adjust the list accordingly,
// stripping out settings from the line if they are discovered.
//
// The supporting TagData() function allows for whitespace if quotes are
// used. For example:
//
// DefaultValue="hello there, how are you"
sLine = ScanAndReplace(sLine, "DefaultValue", ref Overrides);
sLine = ScanAndReplace(sLine, "X", ref Overrides);
sLine = ScanAndReplace(sLine, "Y", ref Overrides);
sLine = ScanAndReplace(sLine, "W", ref Overrides);
sLine = ScanAndReplace(sLine, "H", ref Overrides);
sLine = ScanAndReplace(sLine, "StringStyle", ref Overrides);
sLine = ScanAndReplace(sLine, "StringAlign", ref Overrides);
sLine = ScanAndReplace(sLine, "FocusDismiss", ref Overrides);
sLine = ScanAndReplace(sLine, "FontColor", ref Overrides);
sLine = ScanAndReplace(sLine, "FontFace", ref Overrides);
sLine = ScanAndReplace(sLine, "SolidColor", ref Overrides);
sLine = ScanAndReplace(sLine, "Password", ref Overrides);
sLine = ScanAndReplace(sLine, "FontSize", ref Overrides);
sLine = ScanAndReplace(sLine, "TopMost", ref Overrides);
#endregion
// Get user input
string sInput = GetUserInput(Instance, Overrides);
if (sInput == null)
{
// Rainmeter.Log(Rainmeter.LogLevel.Debug, "InputText: Aborted, user cancelled text box");
return false;
}
// Swap out the $UserInput$ token with what the user typed
sLine = Replace(sLine, "$USERINPUT$", sInput);
}
catch (Exception ex)
{
// If there was an error doing any of the above, log it for debugging purposes.
Rainmeter.Log(Rainmeter.LogLevel.Warning, "InputText: Exception " + ex.GetType().ToString() + ": " + ex.Message);
return false;
}
}
// Execute the bang. This will either be the original line from CommandX= (sLine variable) or
// an adjusted line based on special parsing above.
// Rainmeter.Log(Rainmeter.LogLevel.Debug, "InputText: Executing bang: " + sLine);
Rainmeter.Bang(sLine);
return true;
}
#endregion
#region GetUserInput() -- creates an input textbox and handles all INI and override settings
private string GetUserInput(Rainmeter.Settings.InstanceSettings Instance)
{
// No INI overrides provided, so create an empty list
return GetUserInput(Instance, new Dictionary<string,string>());
}
private string GetUserInput(Rainmeter.Settings.InstanceSettings Instance, Dictionary<string,string> sOverrides)
{
// Create the form. 'InputBox' is a .NET form with a textbox and two button controls on it.
InputBox input = new InputBox();
input.Instance = Instance;
input.ChangeX(Instance, "0");
input.ChangeY(Instance, "0");
// Change the styles of the InputBox form based on overrides or INI values
#region Style and preference tweaks (INI and override settings)
if (sOverrides.ContainsKey("FontFace"))
input.ChangeFontFace(sOverrides["FontFace"]);
else if (!string.IsNullOrEmpty(Instance.INI_Value("FontFace")))
input.ChangeFontFace(Instance.INI_Value("FontFace"));
if (sOverrides.ContainsKey("FontSize"))
input.ChangeFontSize(sOverrides["FontSize"]);
else if (!string.IsNullOrEmpty(Instance.INI_Value("FontSize")))
input.ChangeFontSize(Instance.INI_Value("FontSize"));
if (sOverrides.ContainsKey("W"))
input.ChangeW(sOverrides["W"]);
else if (!string.IsNullOrEmpty(Instance.INI_Value("W")))
input.ChangeW(Instance.INI_Value("W"));
if (sOverrides.ContainsKey("H"))
input.ChangeH(sOverrides["H"]);
else if (!string.IsNullOrEmpty(Instance.INI_Value("H")))
input.ChangeH(Instance.INI_Value("H"));
if (sOverrides.ContainsKey("X"))
input.ChangeX(Instance, sOverrides["X"]);
else if (!string.IsNullOrEmpty(Instance.INI_Value("X")))
input.ChangeX(Instance, Instance.INI_Value("X"));
if (sOverrides.ContainsKey("Y"))
input.ChangeY(Instance, sOverrides["Y"]);
else if (!string.IsNullOrEmpty(Instance.INI_Value("Y")))
input.ChangeY(Instance, Instance.INI_Value("Y"));
if (sOverrides.ContainsKey("StringStyle"))
input.ChangeFontStringStyle(sOverrides["StringStyle"]);
else if (!string.IsNullOrEmpty(Instance.INI_Value("StringStyle")))
input.ChangeFontStringStyle(Instance.INI_Value("StringStyle"));
if (sOverrides.ContainsKey("StringAlign"))
input.ChangeStringAlign(sOverrides["StringAlign"]);
else if (!string.IsNullOrEmpty(Instance.INI_Value("StringAlign")))
input.ChangeStringAlign(Instance.INI_Value("StringAlign"));
bool bFocusDismiss = true;
if (sOverrides.ContainsKey("FocusDismiss"))
{
input.MakeFocusDismiss(sOverrides["FocusDismiss"] == "1");
bFocusDismiss = sOverrides["FocusDismiss"] == "1";
}
else
{
input.MakeFocusDismiss(!(Instance.INI_Value("FocusDismiss").Trim().ToUpper() != "1"));
bFocusDismiss = !(Instance.INI_Value("FocusDismiss").Trim().ToUpper() != "1");
}
if (sOverrides.ContainsKey("FontColor"))
input.ChangeFontColor(sOverrides["FontColor"]);
else if (!string.IsNullOrEmpty(Instance.INI_Value("FontColor")))
input.ChangeFontColor(Instance.INI_Value("FontColor"));
if (sOverrides.ContainsKey("SolidColor"))
input.ChangeBackColor(sOverrides["SolidColor"]);
else if (!string.IsNullOrEmpty(Instance.INI_Value("SolidColor")))
input.ChangeBackColor(Instance.INI_Value("SolidColor"));
if (sOverrides.ContainsKey("Passwords"))
{
if (sOverrides["DefaultValue"] == "1")
input.MakePassword();
}
else if (Instance.INI_Value("Password").Trim().ToUpper() == "1")
input.MakePassword();
bool bAutoTopMost = true;
if (sOverrides.ContainsKey("TopMost"))
{
if (sOverrides["TopMost"] == "1")
{
input.MakeTopmost();
bAutoTopMost = false;
}
else if (sOverrides["TopMost"] == "0")
bAutoTopMost = false;
}
else if (Instance.INI_Value("TopMost").Trim().ToUpper() == "1")
{
input.MakeTopmost();
bAutoTopMost = false;
}
else if (Instance.INI_Value("TopMost").Trim().ToUpper() != "AUTO")
if (!string.IsNullOrEmpty(Instance.INI_Value("TopMost").Trim()))
bAutoTopMost = false;
if (bAutoTopMost)
if (Rainmeter.ParentIsTopmost(Instance))
input.MakeTopmost();
if (sOverrides.ContainsKey("DefaultValue"))
input.DefaultValue(sOverrides["DefaultValue"]);
else if (!string.IsNullOrEmpty(Instance.INI_Value("DefaultValue")))
input.DefaultValue(Instance.INI_Value("DefaultValue").Trim());
#endregion
if (bFocusDismiss)
{
input.Show(new WindowWrapper(Rainmeter.GetConfigWindow(Instance)));
for (; ; )
{
if (input.DialogResult != System.Windows.Forms.DialogResult.None || input.drBackup != System.Windows.Forms.DialogResult.None)
break;
System.Windows.Forms.Application.DoEvents();
System.Threading.Thread.Sleep(44);
}
}
else
{
input.ShowDialog(new WindowWrapper(Rainmeter.GetConfigWindow(Instance)));
}
if (input.drBackup != System.Windows.Forms.DialogResult.None)
{
if (input.drBackup != System.Windows.Forms.DialogResult.OK)
return null;
}
else if (input.DialogResult != System.Windows.Forms.DialogResult.None)
{
if (input.DialogResult != System.Windows.Forms.DialogResult.OK)
return null;
}
Instance.SetTempValue("LastInput", input.sTextValue);
return input.sTextValue;
}
#endregion
#region Replace() -- case-insensitive string replacement
private static string Replace(string sIn, string sFind, string sReplace)
{
int iReplace = sIn.ToUpper().IndexOf(sFind.ToUpper());
string sLineNew = string.Empty;
if (iReplace > 0)
sLineNew += sIn.Substring(0, iReplace);
sLineNew += sReplace;
sLineNew += sIn.Substring(iReplace + (sFind.ToUpper()).Length);
return sLineNew;
}
private static string Replace(string sIn, int iStart, int iLength, string sReplace)
{
int iReplace = iStart;
string sLineNew = string.Empty;
if (iReplace > 0)
sLineNew += sIn.Substring(0, iReplace);
sLineNew += sReplace;
sLineNew += sIn.Substring(iReplace + iLength);
return sLineNew;
}
#endregion
#region TagLoc(), TagData(), FindTag() -- text parsing utilities for the override tags
private int TagLoc(string sLine, string sTag)
{
if (!FindTag(sLine, sTag))
return -1;
return sLine.ToUpper().IndexOf(" " + sTag.ToUpper() + "=") + 1;
}
private string TagData(string sLine, string sTag)
{
if (!FindTag(sLine, sTag))
return string.Empty;
int iStart = TagLoc(sLine, sTag) + sTag.Length + 1;
string sTagData = string.Empty;
bool bInQuote = false;
try
{
for (int i = 0; ; i++)
{
if (i == 0)
{
if (sLine[i + iStart] == '"')
{
bInQuote = true;
continue;
}
}
if (sLine[i + iStart] == '"')
break;
if (!bInQuote)
if (char.IsWhiteSpace(sLine[i + iStart]))
break;
sTagData += sLine[i + iStart];
}
}
catch { }
if (bInQuote == true)
return "\"" + sTagData + "\"";
return sTagData;
}
private bool FindTag(string sLine, string sTag)
{
return (sLine.ToUpper().Contains(" " + sTag.ToUpper() + "="));
}
#endregion
#region ScanAndReplace() -- searches for a tag and its value, adding it to overrides if found, and then removing it from the input line
private string ScanAndReplace(string sLine, string sTagName, ref Dictionary<string, string> Overrides)
{
if (FindTag(sLine, sTagName))
{
string sTagData = TagData(sLine, sTagName);
// Rainmeter.Log(Rainmeter.LogLevel.Debug, "InputText: Overriding " + sTagName + " with " + sTagData);
if (sTagData.StartsWith("\""))
Overrides.Add(sTagName, sTagData.Substring(1, sTagData.Length - 2));
else
Overrides.Add(sTagName, sTagData);
sLine = Replace(sLine, TagLoc(sLine, sTagName) - 1, 1 + sTagName.Length + 1 + sTagData.Length, string.Empty);
}
return sLine;
}
#endregion
#endregion
}
}

View File

@ -0,0 +1,114 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{2CFEC79A-E39E-4FFD-ABC2-C4A69DD1E44D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Rainmeter</RootNamespace>
<AssemblyName>InputText</AssemblyName>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<OldToolsVersion>3.5</OldToolsVersion>
<UpgradeBackupLocation />
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>$(SolutionDir)TestBench\x32\Debug\Plugins\</OutputPath>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<NoWarn>1607</NoWarn>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>$(SolutionDir)TestBench\x32\Release\Plugins\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<NoWarn>1607</NoWarn>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>$(SolutionDir)TestBench\x64\Debug\Plugins\</OutputPath>
<DefineConstants>TRACE;DEBUG;X64</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<NoWarn>1607</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>$(SolutionDir)TestBench\x64\Release\Plugins\</OutputPath>
<DefineConstants>TRACE;X64</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Optimize>true</Optimize>
<DebugType>none</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<NoWarn>1607</NoWarn>
</PropertyGroup>
<PropertyGroup>
<RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Main.cs" />
<Compile Include="PluginCode.cs" />
<Compile Include="Rainmeter.cs" />
<Compile Include="InputBox.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="InputBox.designer.cs">
<DependentUpon>InputBox.cs</DependentUpon>
</Compile>
<Compile Include="$(SolutionDir)Version.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="InputBox.resx">
<DependentUpon>InputBox.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<PropertyGroup>
<PostBuildEvent>"$(SolutionDir)Plugins\API\DllExporter.exe" "$(ConfigurationName)" "$(PlatformName)" "$(TargetDir)\" "$(TargetFileName)" "$(TargetedFrameworkDir)\ilasm.exe" "$(FrameworkSDKDir)bin\ildasm.exe"</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,766 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
// This is a utility class / toolkit for communicating with Rainmeter and managing
// logging, INI settings, bangs, window positioning, multiple instances, and temporary
// data storage.
//
// You should not need to edit this code except to expand the toolkit support.
//
// Rather, most of your plugin's code should go in PluginCode.cs or additional files
// that you create (such as new forms, classes, and controls).
namespace InputText
{
public class WindowWrapper : System.Windows.Forms.IWin32Window
{
public WindowWrapper(IntPtr handle)
{
_hwnd = handle;
}
public IntPtr Handle
{
get { return _hwnd; }
}
private IntPtr _hwnd;
}
public class Rainmeter
{
#region Methods for getting the screen-relative location of the current skin
public static IntPtr GetConfigWindow(Rainmeter.Settings.InstanceSettings Instance)
{
return (IntPtr)(UInt32.Parse(Rainmeter.PluginBridge("GetWindow", Rainmeter.PluginBridge("GetConfig", Instance.INI_File))));
}
public static int ConfigX(string sSkin)
{
IntPtr hwnd = (IntPtr)(UInt32.Parse(Rainmeter.PluginBridge("GetWindow", sSkin)));
RECT rct;
if (!GetWindowRect(hwnd, out rct))
{
Rainmeter.Log(LogLevel.Error, "Rainmeter told us the HWND for window '" + sSkin + "' is " + hwnd.ToInt32().ToString() + "L, but couldn't receive a proper RECT from it");
return 0;
}
return rct.Left;
}
public static int ConfigX(Rainmeter.Settings.InstanceSettings Instance)
{
IntPtr hwnd = (IntPtr)(UInt32.Parse(Rainmeter.PluginBridge("GetWindow", Rainmeter.PluginBridge("GetConfig", Instance.INI_File))));
RECT rct;
if (!GetWindowRect(hwnd, out rct))
{
Rainmeter.Log(LogLevel.Error, "Rainmeter told us the HWND for window '" + Rainmeter.PluginBridge("GetConfig", Instance.INI_File) + "' is " + hwnd.ToInt32().ToString() + "L, but couldn't receive a proper RECT from it");
return 0;
}
return rct.Left;
}
public static int ConfigY(string sSkin)
{
IntPtr hwnd = (IntPtr)(UInt32.Parse(Rainmeter.PluginBridge("GetWindow", sSkin)));
RECT rct;
if (!GetWindowRect(hwnd, out rct))
{
Rainmeter.Log(LogLevel.Error, "Rainmeter told us the HWND for window '" + sSkin + "' is " + hwnd.ToInt32().ToString() + "L, but couldn't receive a proper RECT from it");
return 0;
}
return rct.Top;
}
public static int ConfigY(Rainmeter.Settings.InstanceSettings Instance)
{
IntPtr hwnd = (IntPtr)(UInt32.Parse(Rainmeter.PluginBridge("GetWindow", Rainmeter.PluginBridge("GetConfig", Instance.INI_File))));
RECT rct;
if (!GetWindowRect(hwnd, out rct))
{
Rainmeter.Log(LogLevel.Error, "Rainmeter told us the HWND for window '" + Rainmeter.PluginBridge("GetConfig", Instance.INI_File) + "' is " + hwnd.ToInt32().ToString() + "L, but couldn't receive a proper RECT from it");
return 0;
}
return rct.Top;
}
public static int ConfigWidth(string sSkin)
{
IntPtr hwnd = (IntPtr)(UInt32.Parse(Rainmeter.PluginBridge("GetWindow", sSkin)));
RECT rct;
if (!GetWindowRect(hwnd, out rct))
{
Rainmeter.Log(LogLevel.Error, "Rainmeter told us the HWND for window '" + sSkin + "' is " + hwnd.ToInt32().ToString() + "L, but couldn't receive a proper RECT from it");
return 0;
}
return rct.Right - rct.Left;
}
public static int ConfigWidth(Rainmeter.Settings.InstanceSettings Instance)
{
IntPtr hwnd = (IntPtr)(UInt32.Parse(Rainmeter.PluginBridge("GetWindow", Rainmeter.PluginBridge("GetConfig", Instance.INI_File))));
RECT rct;
if (!GetWindowRect(hwnd, out rct))
{
Rainmeter.Log(LogLevel.Error, "Rainmeter told us the HWND for window '" + Rainmeter.PluginBridge("GetConfig", Instance.INI_File) + "' is " + hwnd.ToInt32().ToString() + "L, but couldn't receive a proper RECT from it");
return 0;
}
return rct.Right - rct.Left;
}
public static int ConfigHeight(string sSkin)
{
IntPtr hwnd = (IntPtr)(UInt32.Parse(Rainmeter.PluginBridge("GetWindow", sSkin)));
RECT rct;
if (!GetWindowRect(hwnd, out rct))
{
Rainmeter.Log(LogLevel.Error, "Rainmeter told us the HWND for window '" + sSkin + "' is " + hwnd.ToInt32().ToString() + "L, but couldn't receive a proper RECT from it");
return 0;
}
return rct.Bottom - rct.Top;
}
public static int ConfigHeight(Rainmeter.Settings.InstanceSettings Instance)
{
IntPtr hwnd = (IntPtr)(UInt32.Parse(Rainmeter.PluginBridge("GetWindow", Rainmeter.PluginBridge("GetConfig", Instance.INI_File))));
RECT rct;
if (!GetWindowRect(hwnd, out rct))
{
Rainmeter.Log(LogLevel.Error, "Rainmeter told us the HWND for window '" + Rainmeter.PluginBridge("GetConfig", Instance.INI_File) + "' is " + hwnd.ToInt32().ToString() + "L, but couldn't receive a proper RECT from it");
return 0;
}
return rct.Bottom - rct.Top;
}
#region GetWindowRect() platform invoke to get the size/location of a window
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
#endregion
#region GetParent() platform invoke to get the handle of a parent window
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
private static extern IntPtr GetParent(IntPtr hWnd);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left; // x position of upper-left corner
public int Top; // y position of upper-left corner
public int Right; // x position of lower-right corner
public int Bottom; // y position of lower-right corner
}
#endregion
#region SendMessage -- SendMessage (this variant is only for WM_COPYSTRUCT messages)
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, ref COPYDATASTRUCT lParam);
[StructLayout(LayoutKind.Sequential)]
struct COPYDATASTRUCT
{
public UInt32 dwData;
public int cbData;
public IntPtr lpData;
}
#endregion
#region FindWindowByClass -- platform invoke to find a window given a class name
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
private static extern IntPtr FindWindowByClass(string lpClassName, IntPtr ZeroOnly);
#endregion
#region GetWindowInfo -- platform invoke to check a window's Z-order (Topmost=Auto)
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowInfo(IntPtr hwnd, ref WINDOWINFO pwi);
[StructLayout(LayoutKind.Sequential)]
private struct WINDOWINFO
{
public uint cbSize;
public RECT rcWindow;
public RECT rcClient;
public uint dwStyle;
public uint dwExStyle;
public uint dwWindowStatus;
public uint cxWindowBorders;
public uint cyWindowBorders;
public ushort atomWindowType;
public ushort wCreatorVersion;
public WINDOWINFO(Boolean? filler)
: this() // Allows automatic initialization of "cbSize" with "new WINDOWINFO(null/true/false)".
{
cbSize = (UInt32)(Marshal.SizeOf(typeof(WINDOWINFO)));
}
}
// Call this function to determine if the parent skin is topmost
public static bool ParentIsTopmost(Rainmeter.Settings.InstanceSettings Instance)
{
IntPtr hwnd = (IntPtr)(UInt32.Parse(Rainmeter.PluginBridge("GetWindow", Rainmeter.PluginBridge("GetConfig", Instance.INI_File))));
WINDOWINFO info = new WINDOWINFO(true);
GetWindowInfo(hwnd, ref info);
return ((info.dwExStyle & 0x00000008L) > 0);
}
#endregion
#region SkinName -- gets the current skin name
public static string SkinName(Rainmeter.Settings.InstanceSettings Instance)
{
try
{
return Instance.ConfigName;
/*
if (Instance.GetTempValue("_internal_SkinPath", string.Empty).ToString() == string.Empty)
{
string sAppDataPath = System.Environment.GetEnvironmentVariable("AppData").Trim();
string sRainmeterINIText = System.IO.File.ReadAllText(sAppDataPath + "\\Rainmeter\\Rainmeter.ini");
string sSkinPath = Chopper(sRainmeterINIText.Replace('\n', '\r'), "SkinPath=", "\r").Trim().TrimEnd(new char[] { '\\' });
Instance.SetTempValue("_internal_SkinPath", sSkinPath);
}
System.IO.FileInfo fi = new System.IO.FileInfo(Instance.INI_File);
return fi.DirectoryName.Replace(Instance.GetTempValue("_internal_SkinPath", string.Empty).ToString(), string.Empty).TrimEnd(new char[] { '\\' }).TrimStart(new char[] { '\\' });
*/
}
catch { }
return string.Empty;
}
#endregion
#endregion
#region Chopper -- string manipulation
public static string Chopper(string sText, string sSearch, string sEnd, int offset)
{
string sIntermediate = "";
try
{
if ((sSearch == null) || (sSearch == string.Empty))
{
sIntermediate = sText.Substring(offset);
}
else
{
if (sText.Contains(sSearch) == false)
return sText;
sIntermediate = sText.Substring(sText.IndexOf(sSearch) + sSearch.Length + offset);
}
if ((sEnd == null) || (sEnd == string.Empty))
return sIntermediate;
if (sIntermediate.Contains(sEnd) == false)
return sIntermediate;
return sIntermediate.Substring(0, sIntermediate.IndexOf(sEnd));
}
catch
{
if (sIntermediate == "")
return sText;
return sIntermediate;
}
}
public static string Chopper(string sText, string sSearch, string sEnd)
{
return Chopper(sText, sSearch, sEnd, 0);
}
#endregion
#region Version helpers (converts "1.04" or "1, 4" to 1004, etc.)
public static UInt32 Version(double dVersion)
{
return (UInt32)(dVersion * 1000.0);
}
public static UInt32 Version(int iMajor, int iMinor)
{
return (UInt32)((iMajor * 1000) + iMinor);
}
#endregion
#region Converts a C# 'string' to a C++ 'char *'
public static unsafe char* String(string s)
{
fixed (char* p = s) return p;
}
#endregion
#region Export for Rainmeter's new plugin bridge
[DllImport("Rainmeter.dll", CharSet = CharSet.Auto)]
private extern static unsafe char* PluginBridge(char* sCommand, char* sData);
private unsafe static string PluginBridge(string sCommand, string sData)
{
try
{
return new string(PluginBridge(Rainmeter.String(sCommand), Rainmeter.String(sData)));
}
catch { }
return string.Empty;
}
#endregion
#region Read INI values using Rainmeter's 'ReadConfigString' export
// We have to use this method rather than loading the .INI file manually because Rainmeter will
// replace tokens for us. See: http://rainmeter.net/RainCMS/?q=Settings_BuiltInVariables
//
// Please note that this is done during plugin initialization and stored in the Instance
// variable. This is done automatically, so this function should not be used by plugin developers
// directly, therefore the methods here are 'private'.
[DllImport("Rainmeter.dll", CharSet = CharSet.Auto)]
private extern static unsafe char* ReadConfigString(char* sSection, char* key, char* defValue);
// If an INI is missing, a blank string will be returned to avoid raising exceptions
private unsafe static string ReadConfigString(string sSection, string sKey)
{
try
{
char* szString = ReadConfigString(Rainmeter.String(sSection), Rainmeter.String(sKey), Rainmeter.String(string.Empty));
if (szString != null)
return new string(szString);
}
catch { }
return string.Empty;
}
#endregion
#region Use Rainmeter's 'LSLog' export to log using its format and settings
[DllImport("Rainmeter.dll", CharSet = CharSet.Auto)]
private extern static unsafe UInt16 LSLog(int nLevel, char* pszModule, char* pszMessage);
public enum LogLevel : int
{
Error = 1,
Warning = 2,
Notice = 3,
Debug = 4
}
// You can call this function directly to log to Rainmeter.log
//
// Rainmeter needs to be configured to allow debug logging, of course.
public static unsafe bool Log(LogLevel level, string sText)
{
return (Rainmeter.LSLog((int)level, Rainmeter.String("C# plugin"), Rainmeter.String(sText)) != 0);
}
#endregion
#region Send a bang to Rainmeter (prepends a '!' if necessary)
public static void Bang(string sBang)
{
if (!sBang.StartsWith("!"))
sBang = "!" + sBang;
System.Diagnostics.Process.Start(System.Windows.Forms.Application.ExecutablePath, sBang);
}
#endregion
#region Settings are automatically created (and set at the top of 'Main.cs'), don't edit here
// WARNING: DO NOT EDIT THIS HERE. Change your author name, version, etc. in 'Main.cs'
public class Settings
{
public string Author = "(unknown)";
public double Version = 0.01;
public string Email = string.Empty;
public string Comments = string.Empty;
public Settings(string _Author, double _Version)
{
this.Author = _Author;
this.Version = _Version;
}
public Settings(string _Author, double _Version, string _Email)
{
this.Author = _Author;
this.Version = _Version;
this.Email = _Email;
}
public Settings(string _Author, double _Version, string _Email, string _Comments)
{
this.Author = _Author;
this.Version = _Version;
this.Email = _Email;
this.Comments = _Comments;
}
public Dictionary<UInt32, InstanceSettings> Instances = new Dictionary<uint, InstanceSettings>();
public List<SectionKey> KeyValues = new List<SectionKey>();
public struct SectionKey
{
public UInt32 id;
public string INI_File;
public string Section;
public string Key;
public string Value;
}
public unsafe void AddInstance(char* iniFile, char* section, UInt32 id)
{
InstanceSettings new_instance = new InstanceSettings();
new_instance.Initialize(this, iniFile, section, id);
this.Instances.Add(id, new_instance);
bool bInSection = false;
foreach (string line in System.IO.File.ReadAllLines(new_instance.INI_File))
{
if (line.Trim().StartsWith(";")) continue; // ignore comments
if (line.Trim().StartsWith("[")) bInSection = false; // new section
// section test
if (line.Trim().ToLower() == ("[" + new_instance.Section.ToLower() + "]"))
bInSection = true;
if (!bInSection) continue; // abort this pass if not in section
if (!line.Contains("=")) continue; // abort this pass if there's no INI setting here
string[] sLineParts = line.Trim().Split(new char[] { '=' });
SectionKey sk = new SectionKey();
sk.id = id;
sk.INI_File = new_instance.INI_File;
sk.Key = sLineParts[0].Trim();
sk.Section = new_instance.Section;
sk.Value = ReadConfigString(new_instance.Section, sLineParts[0].Trim());
this.KeyValues.Add(sk);
}
}
public void RemoveInstance(UInt32 id)
{
try
{
start_over:
for (int i = 0; i < this.KeyValues.Count; i++)
{
if (this.KeyValues[i].id == id)
{
this.KeyValues.RemoveAt(i);
goto start_over; // start over since the IEnumerable has been modified
}
}
this.Instances.Remove(id);
}
catch { }
}
public class InstanceSettings
{
private UInt32 _ID = 0;
private string _INI_File = string.Empty;
private string _Section = string.Empty;
private Settings PluginSettings = null;
private Dictionary<string, object> TempData = new Dictionary<string, object>();
private object locker = new object();
public object GetTempValue(string name, object oDefault)
{
lock (this.locker)
{
if (this.TempData.ContainsKey(name))
return this.TempData[name];
return oDefault;
}
}
public void SetTempValue(string name, object o)
{
lock (this.locker)
{
if (this.TempData.ContainsKey(name))
this.TempData[name] = o;
else
this.TempData.Add(name, o);
}
}
public string INI_Value(string name)
{
try
{
foreach (SectionKey sk in PluginSettings.KeyValues)
if (sk.id == this.ID)
if (sk.Section == this.Section)
if (sk.Key.Trim().ToLower() == name.Trim().ToLower())
return sk.Value;
}
catch { }
return string.Empty;
}
public unsafe void Initialize(Settings _PluginSettings, char* iniFile, char* section, UInt32 id)
{
this.PluginSettings = _PluginSettings;
this._ID = id;
this._INI_File = new string(iniFile);
this._Section = new string(section);
this.ConfigName = Rainmeter.PluginBridge("GetConfig", this.INI_File);
}
public string GetVariable(string sVariable)
{
return Rainmeter.PluginBridge("GetVariable", "\"" + this.ConfigName + "\" " + sVariable.Trim() + "");
}
public string SetVariable(string sVariable, object oData)
{
return Rainmeter.PluginBridge("SetVariable", "\"" + this.ConfigName + "\" " + sVariable.Trim() + " \"" + oData.ToString().Trim() + "\"");
}
public string ConfigName = string.Empty;
public UInt32 ID
{
get
{
return this._ID;
}
set
{
this._ID = value;
}
}
public string INI_File
{
get
{
return this._INI_File;
}
}
public string Section
{
get
{
return this._Section;
}
}
}
}
#endregion
}
public class YourPlugin
{
#region YourPlugin class -- do not modify
// This class is a simple launcher for your actual code in PluginCode.cs
//
// We make use of non-volatile data and threading to let your work run in another
// thread, making Rainmeter nice and responsive. Checks are automatically performed
// so that overlapping of execution does not occur.
// Default values of a blank string for GetUpdate() and zero for Update()/Update2()
// are returned.
public UInt32 Update(Rainmeter.Settings Plugin, UInt32 id)
{
bool bAlreadyRunning = (bool)Plugin.Instances[id].GetTempValue("__RMT_U_AlreadyRunning", false);
if (!bAlreadyRunning)
{
UpdateThread thread_details = new UpdateThread(Plugin.Instances[id]);
Thread thread = new Thread(new ThreadStart(thread_details.Go));
thread.Start();
}
try
{
return (UInt32)Plugin.Instances[id].GetTempValue("__RMT_U_LastValue", 0);
}
catch
{
return 0;
}
}
private class UpdateThread
{
private Rainmeter.Settings.InstanceSettings Instance = null;
public UpdateThread(Rainmeter.Settings.InstanceSettings _Instance)
{
this.Instance = _Instance;
}
public void Go()
{
this.Instance.SetTempValue("__RMT_U_AlreadyRunning", true);
try
{
this.Instance.SetTempValue("__RMT_U_LastValue", new PluginCode().Update(this.Instance));
}
catch (Exception ex)
{
Rainmeter.Log(Rainmeter.LogLevel.Error, "C# plugin in GetString(), " + ex.GetType().ToString() + ": " + ex.Message);
}
this.Instance.SetTempValue("__RMT_U_AlreadyRunning", false);
}
}
public double Update2(Rainmeter.Settings Plugin, UInt32 id)
{
bool bAlreadyRunning = (bool)Plugin.Instances[id].GetTempValue("__RMT_U2_AlreadyRunning", false);
if (!bAlreadyRunning)
{
Update2Thread thread_details = new Update2Thread(Plugin.Instances[id]);
Thread thread = new Thread(new ThreadStart(thread_details.Go));
thread.Start();
}
try
{
return (double)Plugin.Instances[id].GetTempValue("__RMT_U2_LastValue", 0.0);
}
catch
{
return 0.0;
}
}
private class Update2Thread
{
private Rainmeter.Settings.InstanceSettings Instance = null;
public Update2Thread(Rainmeter.Settings.InstanceSettings _Instance)
{
this.Instance = _Instance;
}
public void Go()
{
this.Instance.SetTempValue("__RMT_U2_AlreadyRunning", true);
try
{
this.Instance.SetTempValue("__RMT_U2_LastValue", new PluginCode().Update2(this.Instance));
}
catch (Exception ex)
{
Rainmeter.Log(Rainmeter.LogLevel.Error, "C# plugin in GetString(), " + ex.GetType().ToString() + ": " + ex.Message);
}
this.Instance.SetTempValue("__RMT_U2_AlreadyRunning", false);
}
}
public string GetString(Rainmeter.Settings Plugin, UInt32 id)
{
bool bAlreadyRunning = (bool)Plugin.Instances[id].GetTempValue("__RMT_GS_AlreadyRunning", false);
if (!bAlreadyRunning)
{
GetStringThread thread_details = new GetStringThread(Plugin.Instances[id]);
Thread thread = new Thread(new ThreadStart(thread_details.Go));
thread.Start();
}
try
{
return (string)Plugin.Instances[id].GetTempValue("__RMT_GS_LastValue", string.Empty);
}
catch
{
return string.Empty;
}
}
private class GetStringThread
{
private Rainmeter.Settings.InstanceSettings Instance = null;
public GetStringThread(Rainmeter.Settings.InstanceSettings _Instance)
{
this.Instance = _Instance;
}
public void Go()
{
this.Instance.SetTempValue("__RMT_GS_AlreadyRunning", true);
try
{
this.Instance.SetTempValue("__RMT_GS_LastValue", new PluginCode().GetString(this.Instance));
}
catch (Exception ex)
{
Rainmeter.Log(Rainmeter.LogLevel.Error, "C# plugin in GetString(), " + ex.GetType().ToString() + ": " + ex.Message);
}
this.Instance.SetTempValue("__RMT_GS_AlreadyRunning", false);
}
}
public void ExecuteBang(Rainmeter.Settings Plugin, UInt32 id, string sArguments)
{
bool bAlreadyRunning = (bool)Plugin.Instances[id].GetTempValue("__RMT_EB_AlreadyRunning", false);
if (!bAlreadyRunning)
{
ExecuteBangThread thread_details = new ExecuteBangThread(Plugin.Instances[id], sArguments);
Thread thread = new Thread(new ThreadStart(thread_details.Go));
thread.Start();
}
return;
}
private class ExecuteBangThread
{
private Rainmeter.Settings.InstanceSettings Instance = null;
private string Command = string.Empty;
public ExecuteBangThread(Rainmeter.Settings.InstanceSettings _Instance, string _Command)
{
this.Instance = _Instance;
this.Command = _Command;
}
public void Go()
{
this.Instance.SetTempValue("__RMT_EB_AlreadyRunning", true);
try
{
new PluginCode().ExecuteBang(this.Instance, this.Command);
}
catch (Exception ex)
{
Rainmeter.Log(Rainmeter.LogLevel.Error, "C# plugin in GetString(), " + ex.GetType().ToString() + ": " + ex.Message);
}
this.Instance.SetTempValue("__RMT_EB_AlreadyRunning", false);
}
}
#endregion
}
}