diff --git a/win32/FireflyConfig/App.ico b/win32/FireflyConfig/App.ico new file mode 100644 index 00000000..3a5525fd Binary files /dev/null and b/win32/FireflyConfig/App.ico differ diff --git a/win32/FireflyConfig/AssemblyInfo.cs b/win32/FireflyConfig/AssemblyInfo.cs new file mode 100644 index 00000000..177a4f0e --- /dev/null +++ b/win32/FireflyConfig/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/win32/FireflyConfig/FireflyConfig.cs b/win32/FireflyConfig/FireflyConfig.cs new file mode 100644 index 00000000..7e6259db --- /dev/null +++ b/win32/FireflyConfig/FireflyConfig.cs @@ -0,0 +1,624 @@ +using System; +using System.Drawing; +using System.Collections; +using System.ComponentModel; +using System.Windows.Forms; +using System.Data; +using System.ServiceProcess; +using System.Runtime.InteropServices; +using System.Text; +using JCMLib; + +namespace FireflyConfig +{ + /// + /// Summary description for Form1. + /// + /// + + + public enum ServiceStatus + { + Unintialized, + Running, + Stopped, + Unknown + } + + public class FireflyConfig : System.Windows.Forms.Form + { + private System.Drawing.Icon icnRunning; + private System.Drawing.Icon icnStopped; + private System.Drawing.Icon icnUnknown; + + private Timer timerRefresh; + + private System.ServiceProcess.ServiceController scFirefly; + private ServiceStatus iState = ServiceStatus.Unintialized; + private bool closeFromMenu = false; + + private string strPort; + private string strServerName; + private string strMusicDir; + private string strPassword; + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.TextBox textBoxPort; + private System.Windows.Forms.TextBox textBoxServerName; + private System.Windows.Forms.TextBox textBoxMusicDir; + private System.Windows.Forms.Button buttonBrowseDir; + + private System.Windows.Forms.MenuItem menuItemStart; + private System.Windows.Forms.MenuItem menuItemStop; + private System.Windows.Forms.MenuItem menuItemConfigure; + private System.Windows.Forms.ContextMenu trayMenu; + private NotifyIconEx notifyIcon; + private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog; + private System.Windows.Forms.MenuItem menuItemExit; + private System.Windows.Forms.Button buttonOK; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.TextBox textBoxPassword; + private System.Windows.Forms.CheckBox checkBoxPassword; + private System.ComponentModel.IContainer components; + + public void ServiceStatusUpdate() + { + scFirefly.Refresh(); + ServiceStatus iOldState = iState; + switch(scFirefly.Status) + { + case System.ServiceProcess.ServiceControllerStatus.Stopped: + iState = ServiceStatus.Stopped; + break; + case System.ServiceProcess.ServiceControllerStatus.Running: + iState = ServiceStatus.Running; + break; + default: + iState = ServiceStatus.Unknown; + break; + } + + if(iState != iOldState) { + switch(iState) + { + case ServiceStatus.Stopped: + menuItemStart.Enabled = true; + menuItemStop.Enabled = false; + notifyIcon.Icon = icnStopped; + notifyIcon.Text = "Firefly Media Server is stopped"; + notifyIcon.ShowBalloon("Firefly Server","Server is stopped",JCMLib.NotifyIconEx.NotifyInfoFlags.Info,5000); + break; + case ServiceStatus.Running: + menuItemStart.Enabled = false; + menuItemStop.Enabled = true; + notifyIcon.Icon = icnRunning; + notifyIcon.Text = "Firefly Media Server is running"; + notifyIcon.ShowBalloon("Firefly Server","Server is running",JCMLib.NotifyIconEx.NotifyInfoFlags.Info,5000); + break; + case ServiceStatus.Unknown: + menuItemStart.Enabled = false; + menuItemStop.Enabled = false; + notifyIcon.Icon = icnUnknown; + notifyIcon.Text = "Cannot connect to Firefly Media Server"; + notifyIcon.ShowBalloon("Firefly Server","Cannot contact media server",JCMLib.NotifyIconEx.NotifyInfoFlags.Warning,5000); + break; + } + } + } + + public FireflyConfig() + { + // + // Required for Windows Form Designer support + // + InitializeComponent(); + + // + // TODO: Add any constructor code after InitializeComponent call + // + + /* grab the icons */ + System.IO.Stream st; + System.Reflection.Assembly a = System.Reflection.Assembly.GetExecutingAssembly(); + st = a.GetManifestResourceStream("FireflyConfig.ff_run.ico"); + icnRunning = new System.Drawing.Icon(st); + + st = a.GetManifestResourceStream("FireflyConfig.ff_stop.ico"); + icnStopped = new System.Drawing.Icon(st); + + st = a.GetManifestResourceStream("FireflyConfig.ff_unknown.ico"); + icnUnknown = new System.Drawing.Icon(st); + + /* grab the service handle */ + scFirefly = new System.ServiceProcess.ServiceController("Firefly Media Server"); + + /* set up the poller for service state */ + timerRefresh = new Timer(); + timerRefresh.Interval = 5000; + timerRefresh.Enabled=true; + timerRefresh.Start(); + timerRefresh.Tick += new EventHandler(timerRefresh_Tick); + + this.Visible=false; + + } + + /// + /// Clean up any resources being used. + /// + protected override void Dispose( bool disposing ) + { + if( disposing ) + { + if (components != null) + { + components.Dispose(); + } + } + base.Dispose( disposing ); + } + + protected void LoadIni() + { + string path = Environment.CurrentDirectory + "\\mt-daapd.conf"; + IniFile ifConfig = new IniFile(path); + + strPort = ifConfig.IniReadValue("general","port"); + strServerName = ifConfig.IniReadValue("general","servername"); + strMusicDir = ifConfig.IniReadValue("general","mp3_dir"); + strPassword = ifConfig.IniReadValue("general","password"); + + textBoxPort.Text = strPort; + textBoxServerName.Text = strServerName; + textBoxMusicDir.Text = strMusicDir; + textBoxPassword.Text = strPassword; + if((strPassword == "") || (strPassword == null)) + { + checkBoxPassword.Checked = false; + textBoxPassword.Enabled = false; + } + else + { + checkBoxPassword.Checked = true; + textBoxPassword.Enabled = true; + } + } + + public void timerRefresh_Tick(object sender, EventArgs eArgs) + { + if(sender == timerRefresh) + { + ServiceStatusUpdate(); + } + } + + #region Windows Form Designer generated code + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(FireflyConfig)); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.checkBoxPassword = new System.Windows.Forms.CheckBox(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.textBoxPassword = new System.Windows.Forms.TextBox(); + this.textBoxPort = new System.Windows.Forms.TextBox(); + this.textBoxServerName = new System.Windows.Forms.TextBox(); + this.textBoxMusicDir = new System.Windows.Forms.TextBox(); + this.buttonBrowseDir = new System.Windows.Forms.Button(); + this.buttonOK = new System.Windows.Forms.Button(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.trayMenu = new System.Windows.Forms.ContextMenu(); + this.menuItemConfigure = new System.Windows.Forms.MenuItem(); + this.menuItemStart = new System.Windows.Forms.MenuItem(); + this.menuItemStop = new System.Windows.Forms.MenuItem(); + this.menuItemExit = new System.Windows.Forms.MenuItem(); + this.notifyIcon = new JCMLib.NotifyIconEx(); + this.folderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // label1 + // + this.label1.Location = new System.Drawing.Point(8, 18); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(80, 16); + this.label1.TabIndex = 0; + this.label1.Text = "Port:"; + // + // label2 + // + this.label2.Location = new System.Drawing.Point(8, 79); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(88, 23); + this.label2.TabIndex = 4; + this.label2.Text = "Music Directory:"; + // + // label3 + // + this.label3.Location = new System.Drawing.Point(8, 47); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(80, 23); + this.label3.TabIndex = 2; + this.label3.Text = "Server Name:"; + // + // label4 + // + this.label4.Location = new System.Drawing.Point(16, 50); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(56, 16); + this.label4.TabIndex = 1; + this.label4.Text = "Password:"; + // + // checkBoxPassword + // + this.checkBoxPassword.Location = new System.Drawing.Point(16, 16); + this.checkBoxPassword.Name = "checkBoxPassword"; + this.checkBoxPassword.Size = new System.Drawing.Size(184, 24); + this.checkBoxPassword.TabIndex = 0; + this.checkBoxPassword.Text = "Use Music Library Password"; + this.checkBoxPassword.CheckedChanged += new System.EventHandler(this.checkBoxPassword_CheckedChanged); + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.textBoxPassword); + this.groupBox1.Controls.Add(this.checkBoxPassword); + this.groupBox1.Controls.Add(this.label4); + this.groupBox1.Location = new System.Drawing.Point(8, 112); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(240, 80); + this.groupBox1.TabIndex = 7; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Passsword"; + // + // textBoxPassword + // + this.textBoxPassword.Location = new System.Drawing.Point(80, 48); + this.textBoxPassword.Name = "textBoxPassword"; + this.textBoxPassword.Size = new System.Drawing.Size(144, 20); + this.textBoxPassword.TabIndex = 2; + this.textBoxPassword.Text = ""; + // + // textBoxPort + // + this.textBoxPort.Location = new System.Drawing.Point(96, 16); + this.textBoxPort.Name = "textBoxPort"; + this.textBoxPort.Size = new System.Drawing.Size(48, 20); + this.textBoxPort.TabIndex = 1; + this.textBoxPort.Text = ""; + // + // textBoxServerName + // + this.textBoxServerName.Location = new System.Drawing.Point(96, 48); + this.textBoxServerName.Name = "textBoxServerName"; + this.textBoxServerName.Size = new System.Drawing.Size(152, 20); + this.textBoxServerName.TabIndex = 3; + this.textBoxServerName.Text = ""; + // + // textBoxMusicDir + // + this.textBoxMusicDir.Location = new System.Drawing.Point(96, 80); + this.textBoxMusicDir.Name = "textBoxMusicDir"; + this.textBoxMusicDir.Size = new System.Drawing.Size(120, 20); + this.textBoxMusicDir.TabIndex = 5; + this.textBoxMusicDir.Text = ""; + // + // buttonBrowseDir + // + this.buttonBrowseDir.Location = new System.Drawing.Point(224, 80); + this.buttonBrowseDir.Name = "buttonBrowseDir"; + this.buttonBrowseDir.Size = new System.Drawing.Size(24, 20); + this.buttonBrowseDir.TabIndex = 6; + this.buttonBrowseDir.Text = "..."; + this.buttonBrowseDir.Click += new System.EventHandler(this.buttonBrowseDir_Click); + // + // buttonOK + // + this.buttonOK.DialogResult = System.Windows.Forms.DialogResult.OK; + this.buttonOK.Location = new System.Drawing.Point(8, 216); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(80, 24); + this.buttonOK.TabIndex = 8; + this.buttonOK.Text = "&Ok"; + this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); + // + // buttonCancel + // + this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.buttonCancel.Location = new System.Drawing.Point(168, 216); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(80, 24); + this.buttonCancel.TabIndex = 9; + this.buttonCancel.Text = "&Cancel"; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // trayMenu + // + this.trayMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.menuItemConfigure, + this.menuItemStart, + this.menuItemStop, + this.menuItemExit}); + // + // menuItemConfigure + // + this.menuItemConfigure.DefaultItem = true; + this.menuItemConfigure.Index = 0; + this.menuItemConfigure.Text = "&Configure Firefly Media Server..."; + this.menuItemConfigure.Click += new System.EventHandler(this.menuItemConfigure_Click); + // + // menuItemStart + // + this.menuItemStart.Enabled = false; + this.menuItemStart.Index = 1; + this.menuItemStart.Text = "S&tart Firefly Media Server"; + this.menuItemStart.Click += new System.EventHandler(this.menuItemStart_Click); + // + // menuItemStop + // + this.menuItemStop.Enabled = false; + this.menuItemStop.Index = 2; + this.menuItemStop.Text = "&Stop Firefly Media Server"; + this.menuItemStop.Click += new System.EventHandler(this.menuItemStop_Click); + // + // menuItemExit + // + this.menuItemExit.Index = 3; + this.menuItemExit.Text = "E&xit"; + this.menuItemExit.Click += new System.EventHandler(this.menuItemExit_Click); + // + // notifyIcon + // + this.notifyIcon.ContextMenu = this.trayMenu; + this.notifyIcon.Icon = ((System.Drawing.Icon)(resources.GetObject("notifyIcon.Icon"))); + this.notifyIcon.Text = "Firefly Media Server"; + this.notifyIcon.Visible = true; + this.notifyIcon.DoubleClick += new System.EventHandler(this.notifyIcon_DoubleClick); + // + // FireflyConfig + // + this.AcceptButton = this.buttonOK; + this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); + this.CancelButton = this.buttonCancel; + this.ClientSize = new System.Drawing.Size(256, 246); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.buttonOK); + this.Controls.Add(this.buttonBrowseDir); + this.Controls.Add(this.textBoxMusicDir); + this.Controls.Add(this.textBoxServerName); + this.Controls.Add(this.textBoxPort); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.label3); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "FireflyConfig"; + this.ShowInTaskbar = false; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; + this.Text = "Configuration"; + this.WindowState = System.Windows.Forms.FormWindowState.Minimized; + this.Resize += new System.EventHandler(this.FireflyConfig_Resize); + this.Closing += new System.ComponentModel.CancelEventHandler(this.FireflyConfig_Closing); + this.Load += new System.EventHandler(this.FireflyConfig_Load); + this.groupBox1.ResumeLayout(false); + this.ResumeLayout(false); + + } + #endregion + + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.Run(new FireflyConfig()); + } + + private void notifyIcon_DoubleClick(object sender, System.EventArgs e) + { + LoadIni(); + Show(); + WindowState = FormWindowState.Normal; + ShowInTaskbar = true; + } + + private void FireflyConfig_Closing(object sender, System.ComponentModel.CancelEventArgs e) + { + if(!closeFromMenu) + { + e.Cancel=true; + this.WindowState = FormWindowState.Minimized; + } + else + { + notifyIcon.Visible = false; + } + } + + private void FireflyConfig_Resize(object sender, System.EventArgs e) + { + if(FormWindowState.Minimized == WindowState) + { + Hide(); + } + } + + private void menuItemExit_Click(object sender, System.EventArgs e) + { + closeFromMenu = true; + Close(); + } + + private void FireflyConfig_Load(object sender, System.EventArgs e) + { + Hide(); + } + + private void menuItemConfigure_Click(object sender, System.EventArgs e) + { + LoadIni(); + Show(); + WindowState = FormWindowState.Normal; + ShowInTaskbar = true; + } + + private void menuItemStart_Click(object sender, System.EventArgs e) + { + scFirefly.Start(); + } + + private void menuItemStop_Click(object sender, System.EventArgs e) + { + scFirefly.Stop(); + } + + private void checkBoxPassword_CheckedChanged(object sender, System.EventArgs e) + { + textBoxPassword.Enabled = checkBoxPassword.Checked; + } + + private void buttonCancel_Click(object sender, System.EventArgs e) + { + Hide(); + } + + private void buttonBrowseDir_Click(object sender, System.EventArgs e) + { + folderBrowserDialog.SelectedPath = textBoxMusicDir.Text; + if(folderBrowserDialog.ShowDialog() == DialogResult.OK) + { + textBoxMusicDir.Text = folderBrowserDialog.SelectedPath; + } + + } + + private void buttonOK_Click(object sender, System.EventArgs e) + { + System.Windows.Forms.DialogResult result; + bool changed=false; + string strNewPassword; + + strNewPassword = textBoxPassword.Text; + if(checkBoxPassword.Checked == false) + strNewPassword = ""; + + if(textBoxPort.Text != strPort) + changed = true; + if(textBoxServerName.Text != strServerName) + changed = true; + if(textBoxMusicDir.Text != strMusicDir) + changed = true; + if(strNewPassword != strPassword) + changed = true; + + if(changed) + { + result = MessageBox.Show("Changing these values will require a restart of the Firefly Media Server. Are you sure you want to do this?", + "Restart Confirmation",System.Windows.Forms.MessageBoxButtons.YesNoCancel); + if(result == DialogResult.Yes) + { + /* write the values */ + string path = Environment.CurrentDirectory + "\\mt-daapd.conf"; + IniFile ifConfig = new IniFile(path); + + ifConfig.IniWriteValue("general","port",textBoxPort.Text); + ifConfig.IniWriteValue("general","servername",textBoxServerName.Text); + ifConfig.IniWriteValue("general","mp3_dir",textBoxMusicDir.Text); + ifConfig.IniWriteValue("general","password",strNewPassword); + + try + { + timerRefresh.Enabled = false; + notifyIcon.ShowBalloon("Firefly Server","Stopping Firefly Media Server",JCMLib.NotifyIconEx.NotifyInfoFlags.Info,5000); + scFirefly.Stop(); + scFirefly.WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Stopped,new TimeSpan(0,0,30)); + notifyIcon.ShowBalloon("Firefly Server","Starting Firefly Media Server",JCMLib.NotifyIconEx.NotifyInfoFlags.Info,5000); + scFirefly.Start(); + notifyIcon.ShowBalloon("Firefly Server","Started Firefly Media Server",JCMLib.NotifyIconEx.NotifyInfoFlags.Info,5000); + timerRefresh.Enabled = true; + } + catch (Exception ex) { + ex = ex; + MessageBox.Show("Error restarting server"); + }; + Hide(); + + } + else if(result == DialogResult.No) + { + Hide(); + } + } + else + { + Hide(); + } + } + + } + + public class IniFile + { + public string path; + + [DllImport("kernel32")] + private static extern long WritePrivateProfileString(string section, + string key,string val,string filePath); + [DllImport("kernel32")] + private static extern int GetPrivateProfileString(string section, + string key,string def, StringBuilder retVal, + int size,string filePath); + + /// + /// INIFile Constructor. + /// + /// + public IniFile(string INIPath) + { + path = INIPath; + } + /// + /// Write Data to the INI File + /// + /// + /// Section name + /// + /// Key Name + /// + /// Value Name + public void IniWriteValue(string Section,string Key,string Value) + { + WritePrivateProfileString(Section,Key,Value,this.path); + } + + /// + /// Read Data Value From the Ini File + /// + /// + /// + /// + /// + public string IniReadValue(string Section,string Key) + { + StringBuilder temp = new StringBuilder(4096); + int i = GetPrivateProfileString(Section,Key,"",temp, + 4096, this.path); + return temp.ToString(); + + } + } + +} diff --git a/win32/FireflyConfig/FireflyConfig.csproj b/win32/FireflyConfig/FireflyConfig.csproj new file mode 100644 index 00000000..cba703a3 --- /dev/null +++ b/win32/FireflyConfig/FireflyConfig.csproj @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win32/FireflyConfig/FireflyConfig.resx b/win32/FireflyConfig/FireflyConfig.resx new file mode 100644 index 00000000..b3971cf1 --- /dev/null +++ b/win32/FireflyConfig/FireflyConfig.resx @@ -0,0 +1,355 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + False + + + Private + + + Private + + + False + + + Private + + + Private + + + False + + + Private + + + Private + + + False + + + Private + + + Private + + + False + + + Private + + + Private + + + Private + + + 8, 8 + + + True + + + False + + + True + + + Private + + + Private + + + False + + + Private + + + Private + + + False + + + Private + + + Private + + + Private + + + False + + + Private + + + False + + + Private + + + False + + + Private + + + Private + + + False + + + Private + + + Private + + + False + + + Private + + + Private + + + Private + + + 17, 17 + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + 115, 17 + + + Private + + + + AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAICAgP+AgID/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/gICA/4CAgP8AAAAAAAAAAAAAAAAAAAAAgICA/4CA + gP8AAAAAAAAAAAAAAAAAAAAAAAAAAMDAwP8AAAD/AAAA/wAAAP+AgID/AAAAAAAAAAAAAAAAAAAA/wAA + AP+AgID/gICA/wAAAAAAAAAAAAAAAAAAAADAwMD/AAAA/wAAAP8AAAD/gICA/wAAAAAAAAAAwMDA/wAA + AP8AAAD/AAAA/4CAgP8AAAAAAAAAAAAAAAAAAAAAAAAAAMDAwP8AAAD/AAAA/4CAgP8AAAAAAAAAAMDA + wP8AAAD/AAAA/wAAAP+AgID/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+AgID/AAAAAAAA + AAAAAAAAwMDA/wAAAP8AAAD/gICA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/gICA/wAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAA/4CAgP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/4CA + gP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+AgID/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AP+AgID/gICA/4CAgP+AgID/AAAAAAAAAAAAAAD/gICA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAD/AAAA/wAAAP8AAAD/gICA/4CAgP+AgID/AAAA/4CAgP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP+AgID/AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAD/gICA/wAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADAwMD/wMDA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/4CAgP8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwP/AwMD/AAAA/wAAAP8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA//8AAPP/AADh5wAAwcMAAMGDAADhgwAA+cMAAPnzAAD58wAA+DMAAPgDAAD7gwAA+HMAAPgD + AAD/hwAA//8AAA== + + + + Private + + + 216, 17 + + + Private + + + False + + + (Default) + + + False + + + False + + + FireflyConfig + + + 8, 8 + + + True + + + 80 + + + True + + + Private + + + + AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAABdAP8AXQD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC6PP8Aujz/AF0A/wBdAP8AAAAAAAAAAAAAAAAAAAAAAF0A/wBd + AP8AAAAAAAAAAAAAAAAAAAAAAAAAAJD/tf8Aujz/ALo8/wC6PP8AXQD/AAAAAAAAAAAAAAAAALo8/wC6 + PP8AXQD/AF0A/wAAAAAAAAAAAAAAAAAAAACQ/7X/ALo8/wC6PP8Aujz/AF0A/wAAAAAAAAAAkP+1/wC6 + PP8Aujz/ALo8/wBdAP8AAAAAAAAAAAAAAAAAAAAAAAAAAJD/tf8Aujz/ALo8/wBdAP8AAAAAAAAAAJD/ + tf8Aujz/ALo8/wC6PP8AXQD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC6PP8AXQD/AAAAAAAA + AAAAAAAAkP+1/wC6PP8Aujz/AF0A/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAujz/AF0A/wAA + AAAAAAAAAAAAAAAAAAAAAAAAALo8/wBdAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALo8/wBd + AP8AAAAAAAAAAAAAAAAAAAAAAAAAAAC6PP8AXQD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC6 + PP8AXQD/AF0A/wBdAP8AXQD/AAAAAAAAAAAAujz/AF0A/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAujz/ALo8/wC6PP8Aujz/AF0A/wBdAP8AXQD/ALo8/wBdAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAALo8/wAAAAAAAAAAAAAAAAC6PP8Aujz/ALo8/wC6PP8AXQD/AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAC6PP8Aujz/ALo8/wC6PP8AAAAAAAAAAAAAAAAAujz/AF0A/wAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACQ/7X/kP+1/wC6PP8Aujz/ALo8/wC6PP8Aujz/ALo8/wBdAP8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJD/tf+Q/7X/ALo8/wC6PP8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA//8AAPP/AADh5wAAwcMAAMGDAADhgwAA+cMAAPnzAAD58wAA+DMAAPgDAAD7gwAA+HMAAPgD + AAD/hwAA//8AAA== + + + \ No newline at end of file diff --git a/win32/FireflyConfig/NotifyIconEx.cs b/win32/FireflyConfig/NotifyIconEx.cs new file mode 100644 index 00000000..489482c1 --- /dev/null +++ b/win32/FireflyConfig/NotifyIconEx.cs @@ -0,0 +1,398 @@ +using System; +using System.Drawing; +using System.Windows.Forms; +using System.Runtime.InteropServices; +using System.ComponentModel; +using System.Reflection; + +namespace JCMLib +{ + public class NotifyIconEx : System.ComponentModel.Component + { + #region Notify Icon Target Window + private class NotifyIconTarget : System.Windows.Forms.Form + { + public NotifyIconTarget() + { + this.Text = "Hidden NotifyIconTarget Window"; + } + + protected override void DefWndProc(ref Message msg) + { + if(msg.Msg == 0x400) // WM_USER + { + uint msgId = (uint)msg.LParam; + uint id = (uint)msg.WParam; + + switch(msgId) + { + case 0x201: // WM_LBUTTONDOWN + break; + + case 0x202: // WM_LBUTTONUP + if(ClickNotify != null) + ClickNotify(this, id); + break; + + case 0x203: // WM_LBUTTONDBLCLK + if(DoubleClickNotify != null) + DoubleClickNotify(this, id); + break; + + case 0x205: // WM_RBUTTONUP + if(RightClickNotify != null) + RightClickNotify(this, id); + break; + + case 0x200: // WM_MOUSEMOVE + break; + + case 0x402: // NIN_BALLOONSHOW + break; + + // this should happen when the balloon is closed using the x + // - we never seem to get this message! + case 0x403: // NIN_BALLOONHIDE + break; + + // we seem to get this next message whether the balloon times + // out or whether it is closed using the x + case 0x404: // NIN_BALLOONTIMEOUT + break; + + case 0x405: // NIN_BALLOONUSERCLICK + if(ClickBalloonNotify != null) + ClickBalloonNotify(this, id); + break; + } + } + else if(msg.Msg == 0xC086) // WM_TASKBAR_CREATED + { + if(TaskbarCreated != null) + TaskbarCreated(this, System.EventArgs.Empty); + } + else + { + base.DefWndProc(ref msg); + } + } + + public delegate void NotifyIconHandler(object sender, uint id); + + public event NotifyIconHandler ClickNotify; + public event NotifyIconHandler DoubleClickNotify; + public event NotifyIconHandler RightClickNotify; + public event NotifyIconHandler ClickBalloonNotify; + public event EventHandler TaskbarCreated; + } + #endregion + + #region Platform Invoke + [StructLayout(LayoutKind.Sequential)] private struct NotifyIconData + { + public System.UInt32 cbSize; // DWORD + public System.IntPtr hWnd; // HWND + public System.UInt32 uID; // UINT + public NotifyFlags uFlags; // UINT + public System.UInt32 uCallbackMessage; // UINT + public System.IntPtr hIcon; // HICON + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)] + public System.String szTip; // char[128] + public NotifyState dwState; // DWORD + public NotifyState dwStateMask; // DWORD + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + public System.String szInfo; // char[256] + public System.UInt32 uTimeoutOrVersion; // UINT + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=64)] + public System.String szInfoTitle; // char[64] + public NotifyInfoFlags dwInfoFlags; // DWORD + } + + [DllImport("shell32.Dll")] + private static extern System.Int32 Shell_NotifyIcon(NotifyCommand cmd, ref NotifyIconData data); + + [DllImport("User32.Dll")] + private static extern System.Int32 TrackPopupMenuEx(System.IntPtr hMenu, + System.UInt32 uFlags, + System.Int32 x, + System.Int32 y, + System.IntPtr hWnd, + System.IntPtr ignore); + + [StructLayout(LayoutKind.Sequential)] private struct POINT + { + public System.Int32 x; + public System.Int32 y; + } + + [DllImport("User32.Dll")] + private static extern System.Int32 GetCursorPos(ref POINT point); + + [DllImport("User32.Dll")] + private static extern System.Int32 SetForegroundWindow(System.IntPtr hWnd); + #endregion + + public enum NotifyInfoFlags {Error=0x03, Info=0x01, None=0x00, Warning=0x02} + private enum NotifyCommand {Add=0x00, Delete=0x02, Modify=0x01} + private enum NotifyFlags {Message=0x01, Icon=0x02, Tip=0x04, Info=0x10, State=0x08} + private enum NotifyState {Hidden=0x01} + + private uint m_id = 0; // each icon in the notification area has an id + private IntPtr m_handle; // save the handle so that we can remove icon + private static NotifyIconTarget m_messageSink = new NotifyIconTarget(); + private static uint m_nextId = 1; + private string m_text = ""; + private Icon m_icon = null; + private ContextMenu m_contextMenu = null; + private bool m_visible = false; + private bool m_doubleClick = false; // fix for extra mouse up message we want to discard + + public event EventHandler Click; + public event EventHandler DoubleClick; + public event EventHandler BalloonClick; + + #region Properties + public string Text + { + set + { + if(m_text != value) + { + m_text = value; + CreateOrUpdate(); + } + } + get + { + return m_text; + } + } + + public Icon Icon + { + set + { + m_icon = value; + CreateOrUpdate(); + } + get + { + return m_icon; + } + } + + public ContextMenu ContextMenu + { + set + { + m_contextMenu = value; + } + get + { + return m_contextMenu; + } + } + + public bool Visible + { + set + { + if(m_visible != value) + { + m_visible = value; + CreateOrUpdate(); + } + } + get + { + return m_visible; + } + } + #endregion + + public NotifyIconEx() + { + } + + // this method adds the notification icon if it has not been added and if we + // have enough data to do so + private void CreateOrUpdate() + { + if(this.DesignMode) + return; + + if(m_id == 0) + { + if(m_icon != null) + { + // create icon using available properties + Create(m_nextId++); + } + } + else + { + // update notify icon + Update(); + } + } + + private void Create(uint id) + { + NotifyIconData data = new NotifyIconData(); + data.cbSize = (uint)Marshal.SizeOf(data); + + m_handle = m_messageSink.Handle; + data.hWnd = m_handle; + m_id = id; + data.uID = m_id; + + data.uCallbackMessage = 0x400; + data.uFlags |= NotifyFlags.Message; + + data.hIcon = m_icon.Handle; // this should always be valid + data.uFlags |= NotifyFlags.Icon; + + data.szTip = m_text; + data.uFlags |= NotifyFlags.Tip; + + if(!m_visible) + data.dwState = NotifyState.Hidden; + data.dwStateMask |= NotifyState.Hidden; + + Shell_NotifyIcon(NotifyCommand.Add, ref data); + + // add handlers + m_messageSink.ClickNotify += new NotifyIconTarget.NotifyIconHandler(OnClick); + m_messageSink.DoubleClickNotify += new NotifyIconTarget.NotifyIconHandler(OnDoubleClick); + m_messageSink.RightClickNotify += new NotifyIconTarget.NotifyIconHandler(OnRightClick); + m_messageSink.ClickBalloonNotify += new NotifyIconTarget.NotifyIconHandler(OnClickBalloon); + m_messageSink.TaskbarCreated += new EventHandler(OnTaskbarCreated); + } + + // update an existing icon + private void Update() + { + NotifyIconData data = new NotifyIconData(); + data.cbSize = (uint)Marshal.SizeOf(data); + + data.hWnd = m_messageSink.Handle; + data.uID = m_id; + + data.hIcon = m_icon.Handle; // this should always be valid + data.uFlags |= NotifyFlags.Icon; + + data.szTip = m_text; + data.uFlags |= NotifyFlags.Tip; + data.uFlags |= NotifyFlags.State; + + if(!m_visible) + data.dwState = NotifyState.Hidden; + data.dwStateMask |= NotifyState.Hidden; + + Shell_NotifyIcon(NotifyCommand.Modify, ref data); + } + + protected override void Dispose(bool disposing) + { + Remove(); + base.Dispose(disposing); + } + + public void Remove() + { + if(m_id != 0) + { + // remove the notify icon + NotifyIconData data = new NotifyIconData(); + data.cbSize = (uint)Marshal.SizeOf(data); + + data.hWnd = m_handle; + data.uID = m_id; + + Shell_NotifyIcon(NotifyCommand.Delete, ref data); + + m_id = 0; + } + } + + public void ShowBalloon(string title, string text, NotifyInfoFlags type, int timeoutInMilliSeconds) + { + if(timeoutInMilliSeconds < 0) + throw new ArgumentException("The parameter must be positive", "timeoutInMilliseconds"); + + NotifyIconData data = new NotifyIconData(); + data.cbSize = (uint)Marshal.SizeOf(data); + + data.hWnd = m_messageSink.Handle; + data.uID = m_id; + + data.uFlags = NotifyFlags.Info; + data.uTimeoutOrVersion = (uint)timeoutInMilliSeconds; // this value does not seem to work - any ideas? + data.szInfoTitle = title; + data.szInfo = text; + data.dwInfoFlags = type; + + Shell_NotifyIcon(NotifyCommand.Modify, ref data); + } + + #region Message Handlers + + private void OnClick(object sender, uint id) + { + if(id == m_id) + { + if(!m_doubleClick && Click != null) + Click(this, EventArgs.Empty); + m_doubleClick = false; + } + } + + private void OnRightClick(object sender, uint id) + { + if(id == m_id) + { + // show context menu + if(m_contextMenu != null) + { + POINT point = new POINT(); + GetCursorPos(ref point); + + SetForegroundWindow(m_messageSink.Handle); // this ensures that if we show the menu and then click on another window the menu will close + + // call non public member of ContextMenu + m_contextMenu.GetType().InvokeMember("OnPopup", + BindingFlags.NonPublic|BindingFlags.InvokeMethod|BindingFlags.Instance, + null, m_contextMenu, new Object[] {System.EventArgs.Empty}); + + TrackPopupMenuEx(m_contextMenu.Handle, 64, point.x, point.y, m_messageSink.Handle, IntPtr.Zero); + + // PostMessage(m_messageSink.Handle, 0, IntPtr.Zero, IntPtr.Zero); + } + } + } + + private void OnDoubleClick(object sender, uint id) + { + if(id == m_id) + { + m_doubleClick = true; + if(DoubleClick != null) + DoubleClick(this, EventArgs.Empty); + } + } + + private void OnClickBalloon(object sender, uint id) + { + if(id == m_id) + if(BalloonClick != null) + BalloonClick(this, EventArgs.Empty); + } + + private void OnTaskbarCreated(object sender, EventArgs e) + { + if(m_id != 0) + Create(m_id); // keep the id the same + } + #endregion + } +} diff --git a/win32/FireflyConfig/NotifyIconEx.resx b/win32/FireflyConfig/NotifyIconEx.resx new file mode 100644 index 00000000..dd0ea4d8 --- /dev/null +++ b/win32/FireflyConfig/NotifyIconEx.resx @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.0.0.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + diff --git a/win32/FireflyConfig/ff_run.ico b/win32/FireflyConfig/ff_run.ico new file mode 100644 index 00000000..422c62ad Binary files /dev/null and b/win32/FireflyConfig/ff_run.ico differ diff --git a/win32/FireflyConfig/ff_stop.ico b/win32/FireflyConfig/ff_stop.ico new file mode 100644 index 00000000..3033762d Binary files /dev/null and b/win32/FireflyConfig/ff_stop.ico differ diff --git a/win32/FireflyConfig/ff_unknown.ico b/win32/FireflyConfig/ff_unknown.ico new file mode 100644 index 00000000..3b25fbe0 Binary files /dev/null and b/win32/FireflyConfig/ff_unknown.ico differ diff --git a/win32/mt-daapd.sln b/win32/mt-daapd.sln index a0864683..68b97335 100644 --- a/win32/mt-daapd.sln +++ b/win32/mt-daapd.sln @@ -7,6 +7,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rsp", "rsp.vcproj", "{68CCE ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FireflyConfig", "FireflyConfig\FireflyConfig.csproj", "{842826B0-521A-4296-B2B4-5746BF1C91C2}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -21,6 +25,10 @@ Global {68CCEA19-503F-4894-8AE3-B1673FDEA920}.Debug.Build.0 = Debug|Win32 {68CCEA19-503F-4894-8AE3-B1673FDEA920}.Release.ActiveCfg = Release|Win32 {68CCEA19-503F-4894-8AE3-B1673FDEA920}.Release.Build.0 = Release|Win32 + {842826B0-521A-4296-B2B4-5746BF1C91C2}.Debug.ActiveCfg = Debug|.NET + {842826B0-521A-4296-B2B4-5746BF1C91C2}.Debug.Build.0 = Debug|.NET + {842826B0-521A-4296-B2B4-5746BF1C91C2}.Release.ActiveCfg = Release|.NET + {842826B0-521A-4296-B2B4-5746BF1C91C2}.Release.Build.0 = Release|.NET EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection