Option to automatically check for and notify of new versions.

This commit is contained in:
jdpurcell 2015-01-04 15:04:44 +00:00
parent 6c4a32d517
commit 8c41af53d1
9 changed files with 248 additions and 30 deletions

View File

@ -92,6 +92,10 @@ namespace BizHawk.Client.Common
public bool AVI_CaptureOSD = false;
public bool Screenshot_CaptureOSD = false;
public bool FirstBoot = true;
public bool Update_AutoCheckEnabled = false;
public DateTime? Update_LastCheckTimeUTC = null;
public string Update_LatestVersion = "";
public string Update_IgnoreVersion = "";
//public bool TurboSeek = true; // When PauseOnFrame is set, this will decide whether the client goes into turbo mode or not

View File

@ -1057,6 +1057,9 @@
<Compile Include="tools\Watch\WatchValueBox.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="UpdateChecker.cs">
<SubType>Code</SubType>
</Compile>
<EmbeddedResource Include="AVOut\FFmpegWriterForm.resx">
<DependentUpon>FFmpegWriterForm.cs</DependentUpon>
</EmbeddedResource>

View File

@ -332,6 +332,7 @@
this.CoreNameStatusBarButton = new System.Windows.Forms.ToolStripStatusLabel();
this.ProfileFirstBootLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.LinkConnectStatusBarButton = new System.Windows.Forms.ToolStripStatusLabel();
this.UpdateNotification = new System.Windows.Forms.ToolStripStatusLabel();
this.MainFormContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
this.OpenRomContextMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.LoadLastRomContextMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@ -2751,7 +2752,8 @@
this.KeyPriorityStatusLabel,
this.CoreNameStatusBarButton,
this.ProfileFirstBootLabel,
this.LinkConnectStatusBarButton});
this.LinkConnectStatusBarButton,
this.UpdateNotification});
this.MainStatusBar.Location = new System.Drawing.Point(0, 386);
this.MainStatusBar.Name = "MainStatusBar";
this.MainStatusBar.ShowItemToolTips = true;
@ -2957,6 +2959,17 @@
this.LinkConnectStatusBarButton.ToolTipText = "Link connection is currently enabled";
this.LinkConnectStatusBarButton.Click += new System.EventHandler(this.LinkConnectStatusBarButton_Click);
//
// UpdateNotification
//
this.UpdateNotification.IsLink = true;
this.UpdateNotification.LinkColor = System.Drawing.Color.Red;
this.UpdateNotification.Name = "UpdateNotification";
this.UpdateNotification.Size = new System.Drawing.Size(46, 17);
this.UpdateNotification.Spring = true;
this.UpdateNotification.Text = "New version available!";
this.UpdateNotification.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
this.UpdateNotification.Click += new System.EventHandler(this.UpdateNotification_Click);
//
// MainFormContextMenu
//
this.MainFormContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
@ -3737,6 +3750,7 @@
private System.Windows.Forms.ToolStripMenuItem FlushSaveRAMMenuItem;
private System.Windows.Forms.ToolStripMenuItem PSXDiscControlsMenuItem;
private System.Windows.Forms.ToolStripMenuItem GenesisGameGenieECDC;
private System.Windows.Forms.ToolStripStatusLabel UpdateNotification;
}
}

View File

@ -2252,6 +2252,25 @@ namespace BizHawk.Client.EmuHawk
ProfileFirstBootLabel.Visible = false;
}
private void UpdateNotification_Click(object sender, EventArgs e)
{
GlobalWin.Sound.StopSound();
DialogResult result = MessageBox.Show(this,
"Version " + Global.Config.Update_LatestVersion + " is now available. Would you like to open the BizHawk homepage?\r\n\r\nClick \"No\" to hide the update notification for this version.",
"New Version Available", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
GlobalWin.Sound.StartSound();
if (result == DialogResult.Yes)
{
System.Threading.ThreadPool.QueueUserWorkItem((s) => System.Diagnostics.Process.Start(VersionInfo.HomePage).Dispose());
}
else if (result == DialogResult.No)
{
UpdateChecker.IgnoreNewVersion();
UpdateChecker.BeginCheck(skipCheck: true); // Trigger event to hide new version notification
}
}
#endregion
#region Form Events

View File

@ -47,11 +47,13 @@ namespace BizHawk.Client.EmuHawk
Global.CheatList.Changed += ToolHelpers.UpdateCheatRelatedTools;
// Hide Status bar icons and general statusbar prep
MainStatusBar.Padding = new Padding(MainStatusBar.Padding.Left, MainStatusBar.Padding.Top, MainStatusBar.Padding.Left, MainStatusBar.Padding.Bottom); // Workaround to remove extra padding on right
PlayRecordStatusButton.Visible = false;
AVIStatusLabel.Visible = false;
SetPauseStatusbarIcon();
ToolHelpers.UpdateCheatRelatedTools(null, null);
RebootStatusBarIcon.Visible = false;
UpdateNotification.Visible = false;
StatusBarDiskLightOnImage = Properties.Resources.LightOn;
StatusBarDiskLightOffImage = Properties.Resources.LightOff;
LinkCableOn = Properties.Resources.connect_16x16;
@ -63,6 +65,17 @@ namespace BizHawk.Client.EmuHawk
}
HandleToggleLightAndLink();
// New version notification
UpdateChecker.CheckComplete += (s2, e2) =>
{
if (IsDisposed) return;
BeginInvoke((MethodInvoker)(() =>
{
UpdateNotification.Visible = UpdateChecker.IsNewVersionAvailable;
}));
};
UpdateChecker.BeginCheck(); // Won't actually check unless enabled by user
}
static MainForm()

View File

@ -0,0 +1,143 @@
using System;
using System.IO;
using System.Net;
using System.Threading;
using BizHawk.Client.Common;
namespace BizHawk.Client.EmuHawk
{
public static class UpdateChecker
{
// TODO: Fill in actual URL... for now it will just grab it from right here: [LatestVersion]1.9.2[/LatestVersion]
private static readonly string _latestVersionInfoURL = "http://bizhawk.googlecode.com/svn/trunk/BizHawk.Client.EmuHawk/UpdateChecker.cs";
private static readonly TimeSpan _minimumCheckDuration = TimeSpan.FromHours(8);
private static bool AutoCheckEnabled
{
get { return Global.Config.Update_AutoCheckEnabled; }
set { Global.Config.Update_AutoCheckEnabled = value; }
}
private static DateTime? LastCheckTimeUTC
{
get { return Global.Config.Update_LastCheckTimeUTC; }
set { Global.Config.Update_LastCheckTimeUTC = value; }
}
private static string LatestVersion
{
get { return Global.Config.Update_LatestVersion; }
set { Global.Config.Update_LatestVersion = value; }
}
private static string IgnoreVersion
{
get { return Global.Config.Update_IgnoreVersion; }
set { Global.Config.Update_IgnoreVersion = value; }
}
public static void BeginCheck(bool skipCheck = false)
{
if (skipCheck || String.IsNullOrEmpty(_latestVersionInfoURL) || !AutoCheckEnabled || LastCheckTimeUTC > DateTime.UtcNow - _minimumCheckDuration)
{
OnCheckComplete();
return;
}
ThreadPool.QueueUserWorkItem((s) => CheckInternal());
}
public static bool IsNewVersionAvailable
{
get
{
return AutoCheckEnabled &&
LatestVersion != IgnoreVersion &&
ParseVersion(VersionInfo.MAINVERSION) != 0 && // Avoid notifying if current version string is invalid
ParseVersion(LatestVersion) > ParseVersion(VersionInfo.MAINVERSION);
}
}
public static void IgnoreNewVersion()
{
IgnoreVersion = LatestVersion;
}
public static void ResetHistory()
{
LastCheckTimeUTC = null;
LatestVersion = "";
IgnoreVersion = "";
}
private static void CheckInternal()
{
try
{
string latestVersionInfo = DownloadURLAsString(_latestVersionInfoURL);
LatestVersion = GetVersionNumberFromVersionInfo(latestVersionInfo);
}
catch
{
// Ignore errors, and fall through to set the last check time to avoid requesting too frequently from the web server
}
LastCheckTimeUTC = DateTime.UtcNow;
OnCheckComplete();
}
private static string DownloadURLAsString(string url)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.KeepAlive = false;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (StreamReader responseStream = new StreamReader(response.GetResponseStream()))
{
return responseStream.ReadToEnd();
}
}
private static string GetVersionNumberFromVersionInfo(string info)
{
string versionNumber = GetTextFromTag(info, "VersionNumber");
return (versionNumber != null && ParseVersion(versionNumber) != 0) ? versionNumber : "";
}
private static string GetTextFromTag(string info, string tagName)
{
string openTag = "[" + tagName + "]";
string closeTag = "[/" + tagName + "]";
int start = info.IndexOf(openTag, StringComparison.OrdinalIgnoreCase);
if (start == -1) return null;
start += openTag.Length;
int end = info.IndexOf(closeTag, start, StringComparison.OrdinalIgnoreCase);
if (end == -1) return null;
return info.Substring(start, end - start).Trim();
}
// Major version goes in the first 16 bits, and so on, up to 4 parts
private static ulong ParseVersion(string str)
{
string[] split = str.Split('.');
if (split.Length > 4) return 0;
ulong version = 0;
for (int i = 0; i < split.Length; i++)
{
ushort versionPart;
if (!UInt16.TryParse(split[i], out versionPart)) return 0;
version |= (ulong)versionPart << (48 - (i * 16));
}
return version;
}
private static void OnCheckComplete()
{
CheckComplete(null, EventArgs.Empty);
}
public static event EventHandler CheckComplete = delegate { };
}
}

View File

@ -56,6 +56,7 @@
this.label4 = new System.Windows.Forms.Label();
this.LogWindowAsConsoleCheckbox = new System.Windows.Forms.CheckBox();
this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
this.AutoCheckForUpdates = new System.Windows.Forms.CheckBox();
this.tabControl1.SuspendLayout();
this.tabPage1.SuspendLayout();
this.tabPage3.SuspendLayout();
@ -99,6 +100,7 @@
//
// tabPage1
//
this.tabPage1.Controls.Add(this.AutoCheckForUpdates);
this.tabPage1.Controls.Add(this.StartFullScreenCheckbox);
this.tabPage1.Controls.Add(this.label14);
this.tabPage1.Controls.Add(this.label3);
@ -123,17 +125,17 @@
// StartFullScreenCheckbox
//
this.StartFullScreenCheckbox.AutoSize = true;
this.StartFullScreenCheckbox.Location = new System.Drawing.Point(104, 100);
this.StartFullScreenCheckbox.Location = new System.Drawing.Point(98, 63);
this.StartFullScreenCheckbox.Name = "StartFullScreenCheckbox";
this.StartFullScreenCheckbox.Size = new System.Drawing.Size(110, 17);
this.StartFullScreenCheckbox.TabIndex = 13;
this.StartFullScreenCheckbox.TabIndex = 3;
this.StartFullScreenCheckbox.Text = "Start in Fullscreen";
this.StartFullScreenCheckbox.UseVisualStyleBackColor = true;
//
// label14
//
this.label14.AutoSize = true;
this.label14.Location = new System.Drawing.Point(26, 299);
this.label14.Location = new System.Drawing.Point(26, 246);
this.label14.Name = "label14";
this.label14.Size = new System.Drawing.Size(303, 13);
this.label14.TabIndex = 12;
@ -142,7 +144,7 @@
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(26, 285);
this.label3.Location = new System.Drawing.Point(26, 232);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(272, 13);
this.label3.TabIndex = 11;
@ -151,7 +153,7 @@
// SingleInstanceModeCheckbox
//
this.SingleInstanceModeCheckbox.AutoSize = true;
this.SingleInstanceModeCheckbox.Location = new System.Drawing.Point(6, 265);
this.SingleInstanceModeCheckbox.Location = new System.Drawing.Point(6, 212);
this.SingleInstanceModeCheckbox.Name = "SingleInstanceModeCheckbox";
this.SingleInstanceModeCheckbox.Size = new System.Drawing.Size(127, 17);
this.SingleInstanceModeCheckbox.TabIndex = 10;
@ -161,26 +163,26 @@
// NeverAskSaveCheckbox
//
this.NeverAskSaveCheckbox.AutoSize = true;
this.NeverAskSaveCheckbox.Location = new System.Drawing.Point(6, 146);
this.NeverAskSaveCheckbox.Location = new System.Drawing.Point(6, 109);
this.NeverAskSaveCheckbox.Name = "NeverAskSaveCheckbox";
this.NeverAskSaveCheckbox.Size = new System.Drawing.Size(184, 17);
this.NeverAskSaveCheckbox.TabIndex = 6;
this.NeverAskSaveCheckbox.TabIndex = 5;
this.NeverAskSaveCheckbox.Text = "Never be asked to save changes";
this.NeverAskSaveCheckbox.UseVisualStyleBackColor = true;
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(26, 245);
this.label2.Location = new System.Drawing.Point(26, 192);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(349, 13);
this.label2.TabIndex = 8;
this.label2.TabIndex = 9;
this.label2.Text = "When this is set, the client will receive user input even when focus is lost";
//
// AcceptBackgroundInputCheckbox
//
this.AcceptBackgroundInputCheckbox.AutoSize = true;
this.AcceptBackgroundInputCheckbox.Location = new System.Drawing.Point(6, 225);
this.AcceptBackgroundInputCheckbox.Location = new System.Drawing.Point(6, 172);
this.AcceptBackgroundInputCheckbox.Name = "AcceptBackgroundInputCheckbox";
this.AcceptBackgroundInputCheckbox.Size = new System.Drawing.Size(146, 17);
this.AcceptBackgroundInputCheckbox.TabIndex = 8;
@ -190,49 +192,49 @@
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(26, 201);
this.label1.Location = new System.Drawing.Point(26, 152);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(315, 13);
this.label1.TabIndex = 6;
this.label1.TabIndex = 7;
this.label1.Text = "When this is set, the client will continue to run when it loses focus";
//
// RunInBackgroundCheckbox
//
this.RunInBackgroundCheckbox.AutoSize = true;
this.RunInBackgroundCheckbox.Location = new System.Drawing.Point(6, 181);
this.RunInBackgroundCheckbox.Location = new System.Drawing.Point(6, 132);
this.RunInBackgroundCheckbox.Name = "RunInBackgroundCheckbox";
this.RunInBackgroundCheckbox.Size = new System.Drawing.Size(117, 17);
this.RunInBackgroundCheckbox.TabIndex = 7;
this.RunInBackgroundCheckbox.TabIndex = 6;
this.RunInBackgroundCheckbox.Text = "Run in background";
this.RunInBackgroundCheckbox.UseVisualStyleBackColor = true;
//
// SaveWindowPositionCheckbox
//
this.SaveWindowPositionCheckbox.AutoSize = true;
this.SaveWindowPositionCheckbox.Location = new System.Drawing.Point(6, 123);
this.SaveWindowPositionCheckbox.Location = new System.Drawing.Point(6, 86);
this.SaveWindowPositionCheckbox.Name = "SaveWindowPositionCheckbox";
this.SaveWindowPositionCheckbox.Size = new System.Drawing.Size(133, 17);
this.SaveWindowPositionCheckbox.TabIndex = 5;
this.SaveWindowPositionCheckbox.TabIndex = 4;
this.SaveWindowPositionCheckbox.Text = "Save Window Position";
this.SaveWindowPositionCheckbox.UseVisualStyleBackColor = true;
//
// EnableContextMenuCheckbox
//
this.EnableContextMenuCheckbox.AutoSize = true;
this.EnableContextMenuCheckbox.Location = new System.Drawing.Point(6, 63);
this.EnableContextMenuCheckbox.Location = new System.Drawing.Point(6, 40);
this.EnableContextMenuCheckbox.Name = "EnableContextMenuCheckbox";
this.EnableContextMenuCheckbox.Size = new System.Drawing.Size(128, 17);
this.EnableContextMenuCheckbox.TabIndex = 2;
this.EnableContextMenuCheckbox.TabIndex = 1;
this.EnableContextMenuCheckbox.Text = "Enable Context Menu";
this.EnableContextMenuCheckbox.UseVisualStyleBackColor = true;
//
// StartPausedCheckbox
//
this.StartPausedCheckbox.AutoSize = true;
this.StartPausedCheckbox.Location = new System.Drawing.Point(6, 100);
this.StartPausedCheckbox.Location = new System.Drawing.Point(6, 63);
this.StartPausedCheckbox.Name = "StartPausedCheckbox";
this.StartPausedCheckbox.Size = new System.Drawing.Size(86, 17);
this.StartPausedCheckbox.TabIndex = 4;
this.StartPausedCheckbox.TabIndex = 2;
this.StartPausedCheckbox.Text = "Start paused";
this.StartPausedCheckbox.UseVisualStyleBackColor = true;
//
@ -312,7 +314,7 @@
// BackupSRamCheckbox
//
this.BackupSRamCheckbox.AutoSize = true;
this.BackupSRamCheckbox.Location = new System.Drawing.Point(4, 61);
this.BackupSRamCheckbox.Location = new System.Drawing.Point(6, 61);
this.BackupSRamCheckbox.Name = "BackupSRamCheckbox";
this.BackupSRamCheckbox.Size = new System.Drawing.Size(108, 17);
this.BackupSRamCheckbox.TabIndex = 9;
@ -338,6 +340,16 @@
this.LogWindowAsConsoleCheckbox.Text = "Create the log window as a console window";
this.LogWindowAsConsoleCheckbox.UseVisualStyleBackColor = true;
//
// AutoCheckForUpdates
//
this.AutoCheckForUpdates.AutoSize = true;
this.AutoCheckForUpdates.Location = new System.Drawing.Point(6, 266);
this.AutoCheckForUpdates.Name = "AutoCheckForUpdates";
this.AutoCheckForUpdates.Size = new System.Drawing.Size(288, 17);
this.AutoCheckForUpdates.TabIndex = 13;
this.AutoCheckForUpdates.Text = "Automatically check for and notify me of newer versions";
this.AutoCheckForUpdates.UseVisualStyleBackColor = true;
//
// EmuHawkOptions
//
this.AcceptButton = this.OkBtn;
@ -391,5 +403,6 @@
private System.Windows.Forms.Label label13;
private System.Windows.Forms.Label label14;
private System.Windows.Forms.CheckBox StartFullScreenCheckbox;
private System.Windows.Forms.CheckBox AutoCheckForUpdates;
}
}

View File

@ -29,11 +29,12 @@ namespace BizHawk.Client.EmuHawk
AcceptBackgroundInputCheckbox.Checked = Global.Config.AcceptBackgroundInput;
NeverAskSaveCheckbox.Checked = Global.Config.SupressAskSave;
SingleInstanceModeCheckbox.Checked = Global.Config.SingleInstanceMode;
LogWindowAsConsoleCheckbox.Checked = Global.Config.WIN32_CONSOLE;
AutoCheckForUpdates.Visible = VersionInfo.DeveloperBuild;
AutoCheckForUpdates.Checked = Global.Config.Update_AutoCheckEnabled;
BackupSRamCheckbox.Checked = Global.Config.BackupSaveram;
FrameAdvSkipLagCheckbox.Checked = Global.Config.SkipLagFrame;
LogWindowAsConsoleCheckbox.Checked = Global.Config.WIN32_CONSOLE;
if (LogConsole.ConsoleVisible)
{
@ -46,6 +47,8 @@ namespace BizHawk.Client.EmuHawk
private void OkBtn_Click(object sender, EventArgs e)
{
bool oldUpdateAutoCheckEnabled = Global.Config.Update_AutoCheckEnabled;
Global.Config.StartFullscreen = StartFullScreenCheckbox.Checked;
Global.Config.StartPaused = StartPausedCheckbox.Checked;
Global.Config.PauseWhenMenuActivated = PauseWhenMenuActivatedCheckbox.Checked;
@ -55,12 +58,17 @@ namespace BizHawk.Client.EmuHawk
Global.Config.AcceptBackgroundInput = AcceptBackgroundInputCheckbox.Checked;
Global.Config.SupressAskSave = NeverAskSaveCheckbox.Checked;
Global.Config.SingleInstanceMode = SingleInstanceModeCheckbox.Checked;
Global.Config.WIN32_CONSOLE = LogWindowAsConsoleCheckbox.Checked;
Global.Config.Update_AutoCheckEnabled = AutoCheckForUpdates.Checked;
Global.Config.BackupSaveram = BackupSRamCheckbox.Checked;
Global.Config.SkipLagFrame = FrameAdvSkipLagCheckbox.Checked;
Global.Config.WIN32_CONSOLE = LogWindowAsConsoleCheckbox.Checked;
if (Global.Config.Update_AutoCheckEnabled != oldUpdateAutoCheckEnabled)
{
if (!Global.Config.Update_AutoCheckEnabled) UpdateChecker.ResetHistory();
UpdateChecker.BeginCheck(); // Call even if auto checking is disabled to trigger event (it won't actually check)
}
Close();
DialogResult = DialogResult.OK;

View File

@ -1,8 +1,9 @@
static class VersionInfo
{
public const string MAINVERSION = "1.9.0";
public static string RELEASEDATE = "November 23, 2014";
public static bool DeveloperBuild = true;
public const string MAINVERSION = "1.9.0"; // Use numbers only or the new version notification won't work
public static readonly string RELEASEDATE = "November 23, 2014";
public static readonly bool DeveloperBuild = true;
public static readonly string HomePage = "http://tasvideos.org/BizHawk.html";
public static string GetEmuVersion()
{