diff --git a/Plugins/PluginInputText/AssemblyInfo.cs b/Plugins/PluginInputText/AssemblyInfo.cs index 094bfd12..8c05e710 100644 --- a/Plugins/PluginInputText/AssemblyInfo.cs +++ b/Plugins/PluginInputText/AssemblyInfo.cs @@ -2,6 +2,6 @@ using System.Runtime.CompilerServices; [assembly: AssemblyCopyright("© 2010 - Peter Souza IV")] -[assembly: AssemblyVersion("1.6.0.0")] +[assembly: AssemblyVersion("1.7.0.0")] [assembly: AssemblyInformationalVersion(Rainmeter.Version.Informational)] [assembly: AssemblyProduct("Rainmeter")] diff --git a/Plugins/PluginInputText/InputBox.cs b/Plugins/PluginInputText/InputBox.cs index ba4006aa..d7967808 100644 --- a/Plugins/PluginInputText/InputBox.cs +++ b/Plugins/PluginInputText/InputBox.cs @@ -1,4 +1,22 @@ -using System; +/* + Copyright (C) 2013 Rainmeter Team + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +using System; using System.Drawing; using System.Windows.Forms; @@ -6,14 +24,17 @@ namespace InputText { public partial class InputBox : Form { - public Rainmeter.Settings.InstanceSettings Instance = null; + private SkinWindow parent = null; - #region Default form initializer - public InputBox() + private bool _FocusDismiss = true; + private string _TextValue = string.Empty; + + public InputBox(SkinWindow parent) { + this.parent = parent; + 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). @@ -26,6 +47,14 @@ namespace InputText this.txtInput.Focus(); } + private void InputBox_Load(object sender, EventArgs e) + { + this.Activate(); + this.BringToFront(); + this.Activate(); + this.BringToFront(); + } + // 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. @@ -39,16 +68,13 @@ namespace InputText // } // catch (Exception ex) // { - // Rainmeter.Log(Rainmeter.LogLevel.Warning, "InputText :: exception :: " + ex.GetType().ToString() + ": " + ex.Message); + // API.Log(API.LogType.Warning, "InputText :: exception :: " + ex.GetType().ToString() + ": " + ex.Message); // } - #region TextInput -- returns the inputted text - public string TextInput + #region TextValue -- returns the inputted text + public string TextValue { - get - { - return this.txtInput.Text.Trim(); - } + get { return this._TextValue; } } #endregion #region ChangeFontFace(string) -- changes the text's font name @@ -170,10 +196,10 @@ namespace InputText this.TopMost = true; } #endregion - #region MakePassword() -- causes the textbox to be password style - public void MakePassword() + #region MakePassword(bool) -- causes the textbox to be password style + public void MakePassword(bool bPass) { - this.txtInput.PasswordChar = '*'; + this.txtInput.PasswordChar = bPass ? '*' : '\0'; } #endregion #region ChangeFontStringStyle() -- changes the font's bold/italic styles @@ -216,7 +242,7 @@ namespace InputText } #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) + public void ChangeX(string sX) { try { @@ -227,13 +253,13 @@ namespace InputText // 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); + this.Location = new System.Drawing.Point(this.parent.X + 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) + public void ChangeY(string sY) { try { @@ -244,7 +270,7 @@ namespace InputText // 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)); + this.Location = new System.Drawing.Point(this.Location.X, this.parent.Y + int.Parse(sY)); } catch { } } @@ -256,15 +282,47 @@ namespace InputText } #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; } + #endregion + + #region ShowInputBox() -- shows text input textbox + + private DialogResult drBackup = DialogResult.None; + + public bool ShowInputBox() + { + if (this._FocusDismiss) + { + this.Show(this.parent); + + while (this.DialogResult == DialogResult.None && + this.drBackup == DialogResult.None) + { + Application.DoEvents(); + System.Threading.Thread.Sleep(44); + } + } + else + { + this.ShowDialog(this.parent); + } + + if (this.drBackup != DialogResult.None) + { + if (this.drBackup != DialogResult.OK) + return false; + } + else if (this.DialogResult != DialogResult.None) + { + if (this.DialogResult != DialogResult.OK) + return false; + } + + return true; + } private void txtInput_Leave(object sender, EventArgs e) { @@ -295,8 +353,8 @@ namespace InputText private void btnOK_Click(object sender, EventArgs e) { - _FocusDismiss = false; - this.sTextValue = this.txtInput.Text.Trim(); + this._FocusDismiss = false; + this._TextValue = this.txtInput.Text.Trim(); this.drBackup = DialogResult.OK; this.DialogResult = DialogResult.OK; this.Close(); @@ -304,20 +362,12 @@ namespace InputText private void btnCancel_Click(object sender, EventArgs e) { - _FocusDismiss = false; + this._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(); - } } } diff --git a/Plugins/PluginInputText/Main.cs b/Plugins/PluginInputText/Main.cs index 131181b5..81629e57 100644 --- a/Plugins/PluginInputText/Main.cs +++ b/Plugins/PluginInputText/Main.cs @@ -1,173 +1,148 @@ -using System; +/* + Copyright (C) 2013 Rainmeter Team + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Threading; using Rainmeter; namespace InputText { - public class Main + internal partial class Measure { - /// - /// 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 - /// - private static Rainmeter.Settings Plugin = new Rainmeter.Settings - ( - // Author name - "Peter Souza IV", + private Rainmeter.API rm; - // Version - 1.06, + private string LastInput = string.Empty; + private bool IsExecuteBangRunning = false; - // E-mail - "psouza4@gmail.com", + private object locker = new object(); - // 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() + internal Measure(Rainmeter.API rm) { - return Rainmeter.Version(Plugin.Version); + this.rm = rm; } - [DllExport] - public unsafe static char* GetPluginAuthor() + internal void Reload(Rainmeter.API rm, ref double maxValue) { - 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); + // Do nothing here. } - #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) + internal double Update() { - Plugin.AddInstance(iniFile, section, id); // required: do not remove - - //////////////////////////////////////////////////////////////// - // - // You may add code here, if necessary - // - - //////////////////////////////////////////////////////////////// - return 0; + return 0.0; } - [DllExport] - public static void Finalize(IntPtr instance, UInt32 id) + internal string GetString() { - 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 *** - - - /// - /// 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. - /// - /// The unique instance ID of this request. - /// Current value for this meter. - [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); + lock (this.locker) + { + return this.LastInput; + } } - /// - /// 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. - /// - /// The unique instance ID of this request. - /// Current value for this meter. - //[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); - //} - - /// - /// Rainmeter's request for text data from the plugin. - /// - /// The unique instance ID of this request. - /// Unused still as of Dec 2nd, 2010. - /// - [DllExport] - public unsafe static char* GetString(UInt32 id, UInt32 flags) + internal void ExecuteBang(string args) { - // Do not modify this member. Instead, update your code in 'PluginCode.cs'. - return Rainmeter.String(new YourPlugin().GetString(Plugin, id)); + bool go = false; + + lock (this.locker) + { + if (!this.IsExecuteBangRunning) + { + this.IsExecuteBangRunning = true; + go = true; + } + } + + if (go) + { + ThreadPool.QueueUserWorkItem(ExecuteBangThread, args); + } } - #endregion - - #region ExecuteBang() export -- no need to modify (change code in PluginCode.cs) - - [DllExport] - public static unsafe void ExecuteBang(char* args, UInt32 id) + private void ExecuteBangThread(object state) { - new YourPlugin().ExecuteBang(Plugin, id, new string(args)); - return; - } + string command = (string)state; - #endregion + try + { + ExecuteCommands(command); + } + catch (Exception ex) + { + API.Log(API.LogType.Error, "C# plugin in ExecuteBang(), " + ex.GetType().ToString() + ": " + ex.Message); + } + + lock (this.locker) + { + this.IsExecuteBangRunning = false; + } + } } - /// - /// Dummy attribute to mark method as exported for DllExporter.exe. - /// - [AttributeUsage(AttributeTargets.Method)] - public class DllExport : Attribute + #region Plugin + + public static class Plugin { - public DllExport() + internal static Dictionary Measures = new Dictionary(); + + [DllExport] + public unsafe static void Initialize(void** data, void* rm) { + uint id = (uint)((void*)*data); + Measures.Add(id, new Measure(new Rainmeter.API((IntPtr)rm))); + } + + [DllExport] + public unsafe static void Finalize(void* data) + { + uint id = (uint)data; + Measures.Remove(id); + } + + [DllExport] + public unsafe static void Reload(void* data, void* rm, double* maxValue) + { + uint id = (uint)data; + Measures[id].Reload(new Rainmeter.API((IntPtr)rm), ref *maxValue); + } + + [DllExport] + public unsafe static double Update(void* data) + { + uint id = (uint)data; + return Measures[id].Update(); + } + + [DllExport] + public unsafe static char* GetString(void* data) + { + uint id = (uint)data; + fixed (char* s = Measures[id].GetString()) return s; + } + + [DllExport] + public unsafe static void ExecuteBang(void* data, char* args) + { + uint id = (uint)data; + Measures[id].ExecuteBang(new string(args)); } } + + #endregion } diff --git a/Plugins/PluginInputText/PluginCode.cs b/Plugins/PluginInputText/PluginCode.cs index 2cdfc4fc..1c8f6574 100644 --- a/Plugins/PluginInputText/PluginCode.cs +++ b/Plugins/PluginInputText/PluginCode.cs @@ -1,63 +1,68 @@ -using System; +/* + Copyright (C) 2013 Rainmeter Team + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +using System; using System.Collections.Generic; +using Rainmeter; // The bulk of your plugin's code belongs in this file. namespace InputText { - class PluginCode + internal partial class Measure { - // '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) + private void ExecuteCommands(string Command) { - return 0; - } + Command = Command.Trim(); - //public double Update2(Rainmeter.Settings.InstanceSettings Instance) - //{ - // return 0.0; - //} + // Get default options + Dictionary Options = new Dictionary(); + ReadOption("DefaultValue", Options); + ReadOption("X", Options); + ReadOption("Y", Options); + ReadOption("W", Options); + ReadOption("H", Options); + ReadOption("StringStyle", Options); + ReadOption("StringAlign", Options); + ReadOption("FocusDismiss", Options); + ReadOption("FontColor", Options); + ReadOption("FontFace", Options); + ReadOption("FontSize", Options); + ReadOption("SolidColor", Options); + ReadOption("Password", Options); + ReadOption("TopMost", Options); - 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(" ")) + if (!Command.Contains(" ")) { // Assume that the parameter is the name of the variable - string sVariableName = Command.Trim(); // Ask for input - string sInput = GetUserInput(Instance); + string sInput = GetUserInput(Options); // 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("\"", "\\\"") + "\""); + API.Execute(rm.GetSkin(), "!SetVariable " + Command + " \"" + sInput + "\""); // Note that the skin needs DynamicVariables=1 in the measure's settings or the above // code will have no effect. @@ -68,7 +73,7 @@ namespace InputText #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); + string[] sParts = Command.Split(new string[] { " " }, StringSplitOptions.None); // If the first parameter is 'ExecuteBatch' (not case sensitive)... if (sParts[0].Trim().ToUpper() == "EXECUTEBATCH") @@ -126,18 +131,25 @@ namespace InputText #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. + List commands = new List(); + for (int i = iMin; i <= iMax; i++) { // Read this command's line - string sCurrentLine = Instance.INI_Value("Command" + i.ToString()); + string sCurrentLine = rm.ReadString("Command" + i.ToString(), "", false); // If empty/non-existent, abort if (string.IsNullOrEmpty(sCurrentLine)) break; + commands.Add(sCurrentLine); + } + + foreach (string sCurrentLine in commands) + { // Execute the line, but if there's a problem (error or they cancel the // input textbox), then abort - if (!ExecuteLine(Instance, sCurrentLine)) + if (!ExecuteLine(sCurrentLine, Options)) break; // Continue to the next line, if there is any @@ -147,7 +159,7 @@ namespace InputText } // Unhandled command, log the message but otherwise do nothing - Rainmeter.Log(Rainmeter.LogLevel.Debug, "InputText: Received command \"" + sParts[0].Trim() + "\", left unhandled"); + API.Log(API.LogType.Debug, "InputText: Received command \"" + sParts[0].Trim() + "\", left unhandled"); #endregion @@ -157,7 +169,7 @@ namespace InputText #region This is all code custom to this plugin #region Parse the current command line - private bool ExecuteLine(Rainmeter.Settings.InstanceSettings Instance, string sLine) + private bool ExecuteLine(string sLine, Dictionary Options) { // If this line contains a $UserInput$ token, then we need to do some extra // parsing @@ -186,17 +198,17 @@ namespace InputText sLine = ScanAndReplace(sLine, "FocusDismiss", Overrides); sLine = ScanAndReplace(sLine, "FontColor", Overrides); sLine = ScanAndReplace(sLine, "FontFace", Overrides); + sLine = ScanAndReplace(sLine, "FontSize", Overrides); sLine = ScanAndReplace(sLine, "SolidColor", Overrides); sLine = ScanAndReplace(sLine, "Password", Overrides); - sLine = ScanAndReplace(sLine, "FontSize", Overrides); sLine = ScanAndReplace(sLine, "TopMost", Overrides); #endregion // Get user input - string sInput = GetUserInput(Instance, Overrides); + string sInput = GetUserInput(Options, Overrides); if (sInput == null) { - // Rainmeter.Log(Rainmeter.LogLevel.Debug, "InputText: Aborted, user cancelled text box"); + // API.Log(API.LogType.Debug, "InputText: Aborted, user cancelled text box"); return false; } @@ -206,168 +218,116 @@ namespace InputText 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); + API.Log(API.LogType.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); + // API.Log(API.LogType.Debug, "InputText: Executing bang: " + sLine); + API.Execute(rm.GetSkin(), sLine); return true; } #endregion #region GetUserInput() -- creates an input textbox and handles all INI and override settings - private string GetUserInput(Rainmeter.Settings.InstanceSettings Instance) + delegate void ChangeSettingFromString(string value); + delegate void ChangeInputBoxSetting(string option, ChangeSettingFromString method); + + private string GetUserInput(Dictionary Options) { // No INI overrides provided, so create an empty list - return GetUserInput(Instance, new Dictionary()); + return GetUserInput(Options, new Dictionary()); } - private string GetUserInput(Rainmeter.Settings.InstanceSettings Instance, Dictionary sOverrides) + private string GetUserInput(Dictionary Options, Dictionary Overrides) { + SkinWindow skin = new SkinWindow(rm); + // 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"); + InputBox input = new InputBox(skin); + input.ChangeX("0"); + input.ChangeY("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")) + ChangeInputBoxSetting changeSetting = (opt, change) => { - input.MakeFocusDismiss(sOverrides["FocusDismiss"] == "1"); - bFocusDismiss = sOverrides["FocusDismiss"] == "1"; - } - else + if (Overrides.ContainsKey(opt)) + change(Overrides[opt]); + else if (Options.ContainsKey(opt)) + change(Options[opt]); + }; + + changeSetting("FontFace", input.ChangeFontFace); + changeSetting("FontSize", input.ChangeFontSize); + + changeSetting("W", input.ChangeW); + changeSetting("H", input.ChangeH); + changeSetting("X", input.ChangeX); + changeSetting("Y", input.ChangeY); + + changeSetting("StringStyle", input.ChangeFontStringStyle); + changeSetting("StringAlign", input.ChangeStringAlign); + + changeSetting("FontColor", input.ChangeFontColor); + changeSetting("SolidColor", input.ChangeBackColor); + + if (Overrides.ContainsKey("FocusDismiss")) + input.MakeFocusDismiss(Overrides["FocusDismiss"] == "1"); + else if (Options.ContainsKey("FocusDismiss")) + input.MakeFocusDismiss(Options["FocusDismiss"].Trim() == "1"); + + if (Overrides.ContainsKey("Password")) + input.MakePassword(Overrides["Password"] == "1"); + else if (Options.ContainsKey("Password")) + input.MakePassword(Options["Password"].Trim() == "1"); + + string topmost = null; + if (Overrides.ContainsKey("TopMost")) + topmost = Overrides["TopMost"]; + else if (Options.ContainsKey("TopMost")) + topmost = Options["TopMost"].Trim(); + switch (topmost) { - 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") - { + case "1": input.MakeTopmost(); - bAutoTopMost = false; - } - else if (sOverrides["TopMost"] == "0") - bAutoTopMost = false; + break; + case "0": + break; + default: // AUTO + if (skin.IsTopmost) + input.MakeTopmost(); + break; } - 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()); + changeSetting("DefaultValue", input.DefaultValue); #endregion - if (bFocusDismiss) - { - input.Show(new WindowWrapper(Rainmeter.GetConfigWindow(Instance))); + if (!input.ShowInputBox()) + return null; - 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 + lock (this.locker) { - input.ShowDialog(new WindowWrapper(Rainmeter.GetConfigWindow(Instance))); + this.LastInput = input.TextValue; } - - 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; + return input.TextValue; } #endregion + + #region ReadOption() -- reads given option's value from Rainmeter + private void ReadOption(string optionName, Dictionary Options) + { + string value = rm.ReadString(optionName, ""); + if (!string.IsNullOrEmpty(value)) + { + Options.Add(optionName, value); + } + } + #endregion + #region Replace() -- case-insensitive string replacement private static string Replace(string sIn, string sFind, string sReplace) { @@ -458,7 +418,7 @@ namespace InputText if (FindTag(sLine, sTagName)) { string sTagData = TagData(sLine, sTagName); - // Rainmeter.Log(Rainmeter.LogLevel.Debug, "InputText: Overriding " + sTagName + " with " + sTagData); + // API.Log(API.LogType.Debug, "InputText: Overriding " + sTagName + " with " + sTagData); if (sTagData.StartsWith("\"")) Overrides.Add(sTagName, sTagData.Substring(1, sTagData.Length - 2)); else diff --git a/Plugins/PluginInputText/PluginInputText.csproj b/Plugins/PluginInputText/PluginInputText.csproj index f12a35cf..a7efe612 100644 --- a/Plugins/PluginInputText/PluginInputText.csproj +++ b/Plugins/PluginInputText/PluginInputText.csproj @@ -94,6 +94,7 @@ InputBox.cs + diff --git a/Plugins/PluginInputText/Rainmeter.cs b/Plugins/PluginInputText/Rainmeter.cs index 6c6be2fc..24d55474 100644 --- a/Plugins/PluginInputText/Rainmeter.cs +++ b/Plugins/PluginInputText/Rainmeter.cs @@ -1,11 +1,27 @@ -using System; -using System.Collections.Generic; +/* + Copyright (C) 2013 Rainmeter Team + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +using System; using System.Runtime.InteropServices; -using System.Threading; +using Rainmeter; // This is a utility class / toolkit for communicating with Rainmeter and managing -// logging, INI settings, bangs, window positioning, multiple instances, and temporary -// data storage. +// window positioning. // // You should not need to edit this code except to expand the toolkit support. // @@ -13,119 +29,78 @@ using System.Threading; // that you create (such as new forms, classes, and controls). namespace InputText { - public class WindowWrapper : System.Windows.Forms.IWin32Window + public class SkinWindow : System.Windows.Forms.IWin32Window { - public WindowWrapper(IntPtr handle) + private string _SkinName; + private IntPtr _Handle; + + private int _X = 0; + private int _Y = 0; + private int _W = 0; + private int _H = 0; + + private bool _IsTopmost = false; + + public SkinWindow(Rainmeter.API rm) { - _hwnd = handle; + UpdateStatus(rm); } + #region Methods for getting the screen-relative location of the current skin + public IntPtr Handle { - get { return _hwnd; } + get { return this._Handle; } } - 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) + public int X { - 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; + get { return this._X; } } - public static int ConfigY(string sSkin) + public int Y { - 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; + get { return this._Y; } } - public static int ConfigWidth(string sSkin) + public int Width { - 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; + get { return this._W; } } - public static int ConfigHeight(string sSkin) + public int Height { - 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; + get { return this._H; } } - public static int ConfigHeight(Rainmeter.Settings.InstanceSettings Instance) + + public bool IsTopmost { - IntPtr hwnd = (IntPtr)(UInt32.Parse(Rainmeter.PluginBridge("GetWindow", Rainmeter.PluginBridge("GetConfig", Instance.INI_File)))); - RECT rct; - if (!GetWindowRect(hwnd, out rct)) + get { return this._IsTopmost; } + } + + public void UpdateStatus(Rainmeter.API rm = null) + { + if (rm != null) { - 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; + this._SkinName = rm.GetSkinName(); + this._Handle = rm.GetSkinWindow(); } - return rct.Bottom - rct.Top; + + RECT rct; + if (GetWindowRect(this._Handle, out rct)) + { + this._X = rct.Left; + this._Y = rct.Top; + this._W = rct.Right - rct.Left; + this._H = rct.Bottom - rct.Top; + } + else + { + API.Log(API.LogType.Error, + "Rainmeter told us the HWND for window '" + this._SkinName + "' is " + this._Handle.ToInt32().ToString() + "L, but couldn't receive a proper RECT from it"); + } + + this._IsTopmost = ((GetWindowLong(this._Handle, GWL_EXSTYLE) & WS_EX_TOPMOST) > 0); } #region GetWindowRect() platform invoke to get the size/location of a window @@ -134,12 +109,6 @@ namespace InputText [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 { @@ -149,578 +118,15 @@ namespace InputText public int Bottom; // y position of lower-right corner } #endregion - #region SendMessage -- SendMessage (this variant is only for WM_COPYSTRUCT messages) + #region GetWindowLong() -- platform invoke to check a window's Z-order (Topmost=Auto) - [DllImport("user32.dll", CharSet = CharSet.Auto)] - private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, ref COPYDATASTRUCT lParam); + [DllImport("user32.dll")] + private static extern int GetWindowLong(IntPtr hwnd, int nIndex); - [StructLayout(LayoutKind.Sequential)] - struct COPYDATASTRUCT - { - public UInt32 dwData; - public int cbData; - public IntPtr lpData; - } + private const int GWL_EXSTYLE = -20; + private const int WS_EX_TOPMOST = 8; #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) - { - 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 Instances = new Dictionary(); - public List KeyValues = new List(); - - 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 TempData = new Dictionary(); - - 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) - //{ - // Plugin.Instances[id].SetTempValue("__RMT_U_AlreadyRunning", true); - - // ThreadPool.QueueUserWorkItem(_instance => - // { - // Rainmeter.Settings.InstanceSettings Instance = (Rainmeter.Settings.InstanceSettings)_instance; - - // try - // { - // Instance.SetTempValue("__RMT_U_LastValue", new PluginCode().Update(Instance)); - // } - // catch (Exception ex) - // { - // Rainmeter.Log(Rainmeter.LogLevel.Error, "C# plugin in Update(), " + ex.GetType().ToString() + ": " + ex.Message); - // } - - // Instance.SetTempValue("__RMT_U_AlreadyRunning", false); - // }, Plugin.Instances[id]); - //} - - //try - //{ - // return (UInt32)Plugin.Instances[id].GetTempValue("__RMT_U_LastValue", 0); - //} - //catch - { - return 0; - } - } - - //public double Update2(Rainmeter.Settings Plugin, UInt32 id) - //{ - // bool bAlreadyRunning = (bool)Plugin.Instances[id].GetTempValue("__RMT_U2_AlreadyRunning", false); - // if (!bAlreadyRunning) - // { - // Plugin.Instances[id].SetTempValue("__RMT_U2_AlreadyRunning", true); - - // ThreadPool.QueueUserWorkItem(_instance => - // { - // Rainmeter.Settings.InstanceSettings Instance = (Rainmeter.Settings.InstanceSettings)_instance; - - // try - // { - // Instance.SetTempValue("__RMT_U2_LastValue", new PluginCode().Update2(Instance)); - // } - // catch (Exception ex) - // { - // Rainmeter.Log(Rainmeter.LogLevel.Error, "C# plugin in Update2(), " + ex.GetType().ToString() + ": " + ex.Message); - // } - - // Instance.SetTempValue("__RMT_U2_AlreadyRunning", false); - // }, Plugin.Instances[id]); - // } - - // try - // { - // return (double)Plugin.Instances[id].GetTempValue("__RMT_U2_LastValue", 0.0); - // } - // catch - // { - // return 0.0; - // } - //} - - public string GetString(Rainmeter.Settings Plugin, UInt32 id) - { - bool bAlreadyRunning = (bool)Plugin.Instances[id].GetTempValue("__RMT_GS_AlreadyRunning", false); - if (!bAlreadyRunning) - { - Plugin.Instances[id].SetTempValue("__RMT_GS_AlreadyRunning", true); - - ThreadPool.QueueUserWorkItem(_instance => - { - Rainmeter.Settings.InstanceSettings Instance = (Rainmeter.Settings.InstanceSettings)_instance; - - try - { - Instance.SetTempValue("__RMT_GS_LastValue", new PluginCode().GetString(Instance)); - } - catch (Exception ex) - { - Rainmeter.Log(Rainmeter.LogLevel.Error, "C# plugin in GetString(), " + ex.GetType().ToString() + ": " + ex.Message); - } - - Instance.SetTempValue("__RMT_GS_AlreadyRunning", false); - }, Plugin.Instances[id]); - } - - try - { - return (string)Plugin.Instances[id].GetTempValue("__RMT_GS_LastValue", string.Empty); - } - catch - { - return string.Empty; - } - } - - public void ExecuteBang(Rainmeter.Settings Plugin, UInt32 id, string sArguments) - { - bool bAlreadyRunning = (bool)Plugin.Instances[id].GetTempValue("__RMT_EB_AlreadyRunning", false); - if (!bAlreadyRunning) - { - Plugin.Instances[id].SetTempValue("__RMT_EB_AlreadyRunning", true); - - ThreadPool.QueueUserWorkItem(_param => - { - Rainmeter.Settings.InstanceSettings Instance = (Rainmeter.Settings.InstanceSettings)((ExecuteBangParam)_param).Instance; - string Command = (string)((ExecuteBangParam)_param).Command; - - try - { - new PluginCode().ExecuteBang(Instance, Command); - } - catch (Exception ex) - { - Rainmeter.Log(Rainmeter.LogLevel.Error, "C# plugin in ExecuteBang(), " + ex.GetType().ToString() + ": " + ex.Message); - } - - Instance.SetTempValue("__RMT_EB_AlreadyRunning", false); - }, new ExecuteBangParam(Plugin.Instances[id], sArguments)); - } - return; - } - - private class ExecuteBangParam - { - public Rainmeter.Settings.InstanceSettings Instance = null; - public string Command = string.Empty; - - public ExecuteBangParam(Rainmeter.Settings.InstanceSettings _Instance, string _Command) - { - this.Instance = _Instance; - this.Command = _Command; - } - } #endregion }