diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000..5d449a8a
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,12 @@
+# Contributing
+We'd love to work with you and accept your contributions. For small changes like bug fixes, typos, etc. Please Fork us and submit a pull request with the details of what you have changed.
+
+For larger changes, you will have to electronically sign a statement that indicates two things:
+
+* You are willingly licensing your contributions under the terms of the open source license of the project that you're contributing to.
+
+* You are legally able to license your contributions as stated.
+
+This is called a Contributor Licence Agreement or "CLA" for short.
+
+The standard licence for Xibo is the [AGPLv3](LICENSE). For more information please see [CONTRIBUTING](https://github.com/xibosignage/xibo/blob/master/CONTRIBUTING.md).
\ No newline at end of file
diff --git a/Control/Region.cs b/Control/Region.cs
index 3d29a2b7..341764d4 100644
--- a/Control/Region.cs
+++ b/Control/Region.cs
@@ -1,6 +1,6 @@
/*
* Xibo - Digitial Signage - http://www.xibo.org.uk
- * Copyright (C) 2006-2014 Daniel Garner
+ * Copyright (C) 2006-2015 Daniel Garner
*
* This file is part of Xibo.
*
@@ -38,8 +38,8 @@ class Region : Panel
private Media _media;
private RegionOptions _options;
- public bool _hasExpired = false;
- public bool _layoutExpired = false;
+ private bool _hasExpired = false;
+ private bool _layoutExpired = false;
private int _currentSequence = -1;
// Stat objects
@@ -101,6 +101,23 @@ public RegionOptions regionOptions
}
}
+ ///
+ /// Inform the region that the layout has expired
+ ///
+ public void setLayoutExpired()
+ {
+ _layoutExpired = true;
+ }
+
+ ///
+ /// Has this region expired
+ ///
+ ///
+ public bool hasExpired()
+ {
+ return _hasExpired;
+ }
+
///
/// Evaulates the change in options
///
@@ -343,6 +360,9 @@ private void ParseOptionsForMediaNode(XmlNode mediaNode, XmlAttributeCollection
// There will be some stuff on option nodes
XmlNode optionNode = mediaNode.FirstChild;
+ // Track if an update interval has been provided in the XLF
+ bool updateIntervalProvided = false;
+
// Loop through each option node
foreach (XmlNode option in optionNode.ChildNodes)
{
@@ -371,6 +391,8 @@ private void ParseOptionsForMediaNode(XmlNode mediaNode, XmlAttributeCollection
}
else if (option.Name == "updateInterval")
{
+ updateIntervalProvided = true;
+
try
{
_options.updateInterval = int.Parse(option.InnerText);
@@ -410,6 +432,10 @@ private void ParseOptionsForMediaNode(XmlNode mediaNode, XmlAttributeCollection
_options.javaScript = raw.InnerText;
}
}
+
+ // Media Types without an update interval should be set to something rather high
+ if (!updateIntervalProvided)
+ _options.updateInterval = int.MaxValue;
}
///
@@ -508,10 +534,9 @@ private Media CreateNextMediaNode(RegionOptions options)
///
private void StartMedia(Media media)
{
- media.RenderMedia();
-
Trace.WriteLine(new LogMessage("Region - StartMedia", "Starting media"), LogType.Audit.ToString());
+ media.RenderMedia();
Controls.Add(media);
}
@@ -536,8 +561,7 @@ private void StopMedia(Media media)
}
catch (Exception ex)
{
- Debug.WriteLine("No media to remove");
- Debug.WriteLine(ex.Message);
+ Trace.WriteLine(new LogMessage("Region - Stop Media", "Unable to dispose. Ex = " + ex.Message), LogType.Audit.ToString());
}
}
@@ -585,6 +609,10 @@ private void media_DurationElapsedEvent(int filesPlayed)
// Increment the _current sequence by the number of filesPlayed (minus 1)
_currentSequence = _currentSequence + (filesPlayed - 1);
+ // If this layout has been expired we know that everything will soon be torn down, so do nothing
+ if (_layoutExpired)
+ return;
+
// make some decisions about what to do next
try
{
@@ -641,8 +669,7 @@ protected override void Dispose(bool disposing)
}
catch (Exception ex)
{
- Debug.WriteLine(ex.Message);
- Debug.WriteLine("There was no media to dispose", "Region - Dispose");
+ Trace.WriteLine(new LogMessage("Region - Dispose", "Unable to dispose media. Ex = " + ex.Message), LogType.Audit.ToString());
}
finally
{
diff --git a/Log/ClientInfo.cs b/Log/ClientInfo.cs
index 08fcc1d3..13f4b14b 100644
--- a/Log/ClientInfo.cs
+++ b/Log/ClientInfo.cs
@@ -162,6 +162,10 @@ public void AddToLogGrid(string message, LogType logType)
return;
}
+ // Prevent the log grid getting too large (clear at 500 messages)
+ if (logDataGridView.RowCount > 500)
+ logDataGridView.Rows.Clear();
+
int newRow = logDataGridView.Rows.Add();
LogMessage logMessage;
diff --git a/Log/LogMessage.cs b/Log/LogMessage.cs
index 940234ec..a85b9a43 100644
--- a/Log/LogMessage.cs
+++ b/Log/LogMessage.cs
@@ -97,10 +97,10 @@ public override string ToString()
// Just do this with a string builder rather than an XML builder.
String theMessage;
- theMessage = String.Format("{0}", SecurityElement.Escape(_message));
- theMessage += String.Format("{0}", _method);
- theMessage += String.Format("{0}", LogDate);
+ theMessage = String.Format("{0}", LogDate);
theMessage += String.Format("{0}", _thread);
+ theMessage += String.Format("{0}", _method);
+ theMessage += String.Format("{0}", SecurityElement.Escape(_message));
if (_scheduleId != 0) theMessage += String.Format("{0}", _scheduleId.ToString());
if (_layoutId != 0) theMessage += String.Format("{0}", _scheduleId.ToString());
diff --git a/Log/StatLog.cs b/Log/StatLog.cs
index 17ac52dd..a56934e1 100644
--- a/Log/StatLog.cs
+++ b/Log/StatLog.cs
@@ -1,6 +1,6 @@
/*
* Xibo - Digitial Signage - http://www.xibo.org.uk
- * Copyright (C) 2009-2014 Spring Signage Ltd
+ * Copyright (C) 2009-2015 Spring Signage Ltd
*
* This file is part of Xibo.
*
@@ -32,6 +32,7 @@ namespace XiboClient
{
class StatLog
{
+ public static object _locker = new object();
private Collection _stats;
private HardwareKey _hardwareKey;
@@ -194,58 +195,73 @@ private void FlushToFile()
///
private void ProcessQueueToXmds()
{
- Debug.WriteLine(new LogMessage("FlushToXmds", String.Format("IN")), LogType.Audit.ToString());
-
- // If we haven't had a successful connection recently, then don't log
- if (ApplicationSettings.Default.XmdsLastConnection.AddSeconds((int)ApplicationSettings.Default.CollectInterval) < DateTime.Now)
- return;
-
- // Get a list of all the log files waiting to be sent to XMDS.
- string[] logFiles = Directory.GetFiles(ApplicationSettings.Default.LibraryPath, "*" + ApplicationSettings.Default.StatsLogFile + "*");
-
- foreach (string fileName in logFiles)
+ try
{
- // If we have some, create an XMDS object
- using (xmds.xmds logtoXmds = new xmds.xmds())
- {
- logtoXmds.Url = ApplicationSettings.Default.XiboClient_xmds_xmds;
-
- // construct the log message
- StringBuilder builder = new StringBuilder();
- builder.Append("");
-
- foreach (string entry in File.ReadAllLines(fileName))
- builder.Append(entry);
-
- builder.Append("");
+ // If we haven't had a successful connection recently, then don't log
+ if (ApplicationSettings.Default.XmdsLastConnection.AddSeconds((int)ApplicationSettings.Default.CollectInterval) < DateTime.Now)
+ return;
- try
- {
- logtoXmds.SubmitStats(ApplicationSettings.Default.ServerKey, _hardwareKey.Key, builder.ToString());
-
- // Delete the file we are on
- File.Delete(fileName);
- }
- catch (WebException webEx)
- {
- // Increment the quantity of XMDS failures and bail out
- ApplicationSettings.Default.IncrementXmdsErrorCount();
+ lock (_locker)
+ {
+ // Get a list of all the log files waiting to be sent to XMDS.
+ string[] logFiles = Directory.GetFiles(ApplicationSettings.Default.LibraryPath, "*" + ApplicationSettings.Default.StatsLogFile + "*");
- // Log this message, but dont abort the thread
- Trace.WriteLine(new LogMessage("ProcessQueueToXmds", "WebException: " + webEx.Message), LogType.Error.ToString());
+ // Track processed files
+ int filesProcessed = 0;
- // Drop out the loop
- break;
- }
- catch (Exception e)
+ // Loop through each file
+ foreach (string fileName in logFiles)
{
- Trace.WriteLine(new LogMessage("FlushToXmds", string.Format("Exception when submitting to XMDS: {0}", e.Message)), LogType.Error.ToString());
+ // Only process as many files in one go as configured
+ if (filesProcessed >= ApplicationSettings.Default.MaxLogFileUploads)
+ break;
+
+ // If we have some, create an XMDS object
+ using (xmds.xmds logtoXmds = new xmds.xmds())
+ {
+ logtoXmds.Url = ApplicationSettings.Default.XiboClient_xmds_xmds;
+
+ // construct the log message
+ StringBuilder builder = new StringBuilder();
+ builder.Append("");
+
+ foreach (string entry in File.ReadAllLines(fileName))
+ builder.Append(entry);
+
+ builder.Append("");
+
+ try
+ {
+ logtoXmds.SubmitStats(ApplicationSettings.Default.ServerKey, _hardwareKey.Key, builder.ToString());
+
+ // Delete the file we are on
+ File.Delete(fileName);
+ }
+ catch (WebException webEx)
+ {
+ // Increment the quantity of XMDS failures and bail out
+ ApplicationSettings.Default.IncrementXmdsErrorCount();
+
+ // Log this message, but dont abort the thread
+ Trace.WriteLine(new LogMessage("ProcessQueueToXmds", "WebException: " + webEx.Message), LogType.Error.ToString());
+
+ // Drop out the loop
+ break;
+ }
+ catch (Exception e)
+ {
+ Trace.WriteLine(new LogMessage("FlushToXmds", string.Format("Exception when submitting to XMDS: {0}", e.Message)), LogType.Error.ToString());
+ }
+
+ filesProcessed++;
+ }
}
}
}
-
- // Log out
- Debug.WriteLine(new LogMessage("FlushToXmds", String.Format("OUT")), LogType.Audit.ToString());
+ catch (Exception e)
+ {
+ Trace.WriteLine(new LogMessage("FlushToXmds", string.Format("Unknown Exception: {0}", e.Message)), LogType.Error.ToString());
+ }
}
}
diff --git a/Log/XiboTraceListener.cs b/Log/XiboTraceListener.cs
index 2db7a382..9b777311 100644
--- a/Log/XiboTraceListener.cs
+++ b/Log/XiboTraceListener.cs
@@ -1,6 +1,6 @@
/*
* Xibo - Digitial Signage - http://www.xibo.org.uk
- * Copyright (C) 2006-2012 Daniel Garner
+ * Copyright (C) 2006-2015 Daniel Garner, Spring Signage Ltd
*
* This file is part of Xibo.
*
@@ -35,6 +35,7 @@ namespace XiboClient
{
class XiboTraceListener : TraceListener
{
+ public static object _locker = new object();
private Collection _traceMessages;
private string _logPath;
private HardwareKey _hardwareKey;
@@ -146,53 +147,74 @@ private void FlushToFile()
///
public void ProcessQueueToXmds()
{
- // If we haven't had a successful connection recently, then don't log
- if (ApplicationSettings.Default.XmdsLastConnection.AddSeconds((int)ApplicationSettings.Default.CollectInterval) < DateTime.Now)
- return;
-
- // Get a list of all the log files waiting to be sent to XMDS.
- string[] logFiles = Directory.GetFiles(ApplicationSettings.Default.LibraryPath, "*" + ApplicationSettings.Default.LogLocation + "*");
-
- foreach (string fileName in logFiles)
+ try
{
- // If we have some, create an XMDS object
- using (xmds.xmds logtoXmds = new xmds.xmds())
- {
- logtoXmds.Url = ApplicationSettings.Default.XiboClient_xmds_xmds;
-
- // construct the log message
- StringBuilder builder = new StringBuilder();
- builder.Append("");
-
- foreach (string entry in File.ReadAllLines(fileName))
- builder.Append(entry);
-
- builder.Append("");
+ // If we haven't had a successful connection recently, then don't log
+ if (ApplicationSettings.Default.XmdsLastConnection.AddSeconds((int)ApplicationSettings.Default.CollectInterval) < DateTime.Now)
+ return;
- try
- {
- logtoXmds.SubmitLog(ApplicationSettings.Default.ServerKey, _hardwareKey.Key, builder.ToString());
-
- // Delete the file we are on
- File.Delete(fileName);
- }
- catch (WebException webEx)
- {
- // Increment the quantity of XMDS failures and bail out
- ApplicationSettings.Default.IncrementXmdsErrorCount();
+ lock (_locker)
+ {
+ // Get a list of all the log files waiting to be sent to XMDS.
+ string[] logFiles = Directory.GetFiles(ApplicationSettings.Default.LibraryPath, "*" + ApplicationSettings.Default.LogLocation + "*");
- // Log this message, but dont abort the thread
- Trace.WriteLine(new LogMessage("ProcessQueueToXmds", "WebException: " + webEx.Message), LogType.Error.ToString());
+ // Track processed files
+ int filesProcessed = 0;
- // Drop out the loop
- break;
- }
- catch (Exception e)
+ // Loop through each file
+ foreach (string fileName in logFiles)
{
- Trace.WriteLine(new LogMessage("ProcessQueueToXmds", string.Format("Exception when submitting to XMDS: {0}", e.Message)), LogType.Error.ToString());
+ // Only process as many files in one go as configured
+ if (filesProcessed >= ApplicationSettings.Default.MaxLogFileUploads)
+ break;
+
+ // If we have some, create an XMDS object
+ using (xmds.xmds logtoXmds = new xmds.xmds())
+ {
+ logtoXmds.Url = ApplicationSettings.Default.XiboClient_xmds_xmds;
+
+ // construct the log message
+ StringBuilder builder = new StringBuilder();
+ builder.Append("");
+
+ foreach (string entry in File.ReadAllLines(fileName))
+ builder.Append(entry);
+
+ builder.Append("");
+
+ try
+ {
+ logtoXmds.SubmitLog(ApplicationSettings.Default.ServerKey, _hardwareKey.Key, builder.ToString());
+
+ // Delete the file we are on
+ File.Delete(fileName);
+ }
+ catch (WebException webEx)
+ {
+ // Increment the quantity of XMDS failures and bail out
+ ApplicationSettings.Default.IncrementXmdsErrorCount();
+
+ // Log this message, but dont abort the thread
+ Trace.WriteLine(new LogMessage("ProcessQueueToXmds", "WebException: " + webEx.Message), LogType.Error.ToString());
+
+ // Drop out the loop
+ break;
+ }
+ catch (Exception e)
+ {
+ Trace.WriteLine(new LogMessage("ProcessQueueToXmds", string.Format("Exception when submitting to XMDS: {0}", e.Message)), LogType.Error.ToString());
+ }
+
+ filesProcessed++;
+ }
}
}
}
+ catch (Exception e)
+ {
+ // Do nothing - we just have an unknown exception in logging
+ Trace.WriteLine(new LogMessage("ProcessQueueToXmds", string.Format("Unknown Exception: {0}", e.Message)), LogType.Error.ToString());
+ }
}
public override void Write(string message)
diff --git a/Logic/ApplicationSettings.cs b/Logic/ApplicationSettings.cs
index 39657864..00432ae4 100644
--- a/Logic/ApplicationSettings.cs
+++ b/Logic/ApplicationSettings.cs
@@ -1,6 +1,6 @@
/*
* Xibo - Digitial Signage - http://www.xibo.org.uk
- * Copyright (C) 2006-14 Spring Signage Ltd
+ * Copyright (C) 2006-15 Spring Signage Ltd
*
* This file is part of Xibo.
*
@@ -36,9 +36,9 @@ public class ApplicationSettings
private static string _default = "default";
// Application Specific Settings we want to protect
- private string _clientVersion = "1.7.0";
+ private string _clientVersion = "1.7.1";
private string _version = "4";
- private int _clientCodeVersion = 104;
+ private int _clientCodeVersion = 105;
public string ClientVersion { get { return _clientVersion; } }
public string Version { get { return _version; } }
@@ -160,6 +160,9 @@ public object this[string propertyName]
public int MaxConcurrentDownloads { get; set; }
public int ScreenShotRequestInterval { get; set; }
+ private int _maxLogFileUploads;
+ public int MaxLogFileUploads { get { return ((_maxLogFileUploads == 0) ? 3 : _maxLogFileUploads); } set { _maxLogFileUploads = value; } }
+
public bool PowerpointEnabled { get; set; }
public bool StatsEnabled { get; set; }
public bool ExpireModifiedLayouts { get; set; }
diff --git a/Logic/CacheManager.cs b/Logic/CacheManager.cs
index 19b783b6..0df062c4 100644
--- a/Logic/CacheManager.cs
+++ b/Logic/CacheManager.cs
@@ -276,18 +276,6 @@ public bool IsValidLayout(string layoutFile)
break;
- case "localvideo":
-
- // Check that the path they have specified is ok
- if (!File.Exists(Uri.UnescapeDataString(GetUri(media)).Replace('+', ' ')))
- {
- // Local video path does not exist
- Trace.WriteLine(new LogMessage("CacheManager - IsValidLayout", media.InnerText + " does not exist"), LogType.Error.ToString());
- countInvalidLocalVideo++;
- }
-
- break;
-
default:
continue;
}
diff --git a/Logic/MediaOption.cs b/Logic/MediaOption.cs
index ee39463e..21c1d7dd 100644
--- a/Logic/MediaOption.cs
+++ b/Logic/MediaOption.cs
@@ -70,7 +70,7 @@ public string Get(string name)
return option.Value;
}
- throw new IndexOutOfRangeException("No such option");
+ return string.Empty;
}
public string Get(string name, string def)
diff --git a/MainForm.cs b/MainForm.cs
index cbabb2d6..21db446c 100644
--- a/MainForm.cs
+++ b/MainForm.cs
@@ -45,7 +45,7 @@ public partial class MainForm : Form
{
private Schedule _schedule;
private Collection _regions;
- private bool _isExpired = false;
+ private bool _changingLayout = false;
private int _scheduleId;
private int _layoutId;
private bool _screenSaver = false;
@@ -398,7 +398,10 @@ private void SetCacheManager()
///
void schedule_ScheduleChangeEvent(string layoutPath, int scheduleId, int layoutId)
{
- Trace.WriteLine(new LogMessage("MainForm - ScheduleChangeEvent", string.Format("Schedule Changing to {0}", layoutPath)), LogType.Audit.ToString());
+ Trace.WriteLine(new LogMessage("MainForm - ScheduleChangeEvent", string.Format("Schedule Changing to {0}", layoutPath)), LogType.Audit.ToString());
+
+ // We are changing the layout
+ _changingLayout = true;
_scheduleId = scheduleId;
_layoutId = layoutId;
@@ -429,32 +432,68 @@ private void ChangeToNextLayout(string layoutPath)
try
{
SetThreadExecutionState(EXECUTION_STATE.ES_DISPLAY_REQUIRED | EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
+ }
+ catch
+ {
+ Trace.WriteLine(new LogMessage("MainForm - ChangeToNextLayout", "Unable to set Thread Execution state"), LogType.Info.ToString());
+ }
- // TODO: Check we are never out of the UI thread at this point
-
- DestroyLayout();
+ try
+ {
+ // Destroy the Current Layout
+ try
+ {
+ DestroyLayout();
+ }
+ catch (Exception e)
+ {
+ // Force collect all controls
+ foreach (System.Windows.Forms.Control control in Controls)
+ {
+ control.Dispose();
+ Controls.Remove(control);
+ }
- _isExpired = false;
+ Trace.WriteLine(new LogMessage("MainForm - ChangeToNextLayout", "Destroy Layout Failed. Exception raised was: " + e.Message), LogType.Error.ToString());
+ throw e;
+ }
- PrepareLayout(layoutPath);
+ // Prepare the next layout
+ try
+ {
+ PrepareLayout(layoutPath);
+ _clientInfoForm.CurrentLayoutId = layoutPath;
- _clientInfoForm.CurrentLayoutId = layoutPath;
+ }
+ catch (Exception e)
+ {
+ DestroyLayout();
+ Trace.WriteLine(new LogMessage("MainForm - ChangeToNextLayout", "Prepare Layout Failed. Exception raised was: " + e.Message), LogType.Error.ToString());
+ throw e;
+ }
// Do we need to notify?
- if (ApplicationSettings.Default.SendCurrentLayoutAsStatusUpdate)
+ try
{
- using (xmds.xmds statusXmds = new xmds.xmds())
+ if (ApplicationSettings.Default.SendCurrentLayoutAsStatusUpdate)
{
- statusXmds.Url = ApplicationSettings.Default.XiboClient_xmds_xmds;
- statusXmds.NotifyStatusAsync(ApplicationSettings.Default.Version, ApplicationSettings.Default.ServerKey, ApplicationSettings.Default.HardwareKey, "{\"currentLayoutId\":" + _layoutId + "}");
+ using (xmds.xmds statusXmds = new xmds.xmds())
+ {
+ statusXmds.Url = ApplicationSettings.Default.XiboClient_xmds_xmds;
+ statusXmds.NotifyStatusAsync(ApplicationSettings.Default.Version, ApplicationSettings.Default.ServerKey, ApplicationSettings.Default.HardwareKey, "{\"currentLayoutId\":" + _layoutId + "}");
+ }
}
}
+ catch (Exception e)
+ {
+ Trace.WriteLine(new LogMessage("MainForm - ChangeToNextLayout", "Notify Status Failed. Exception raised was: " + e.Message), LogType.Error.ToString());
+ throw e;
+ }
}
catch (Exception ex)
{
Trace.WriteLine(new LogMessage("MainForm - ChangeToNextLayout", "Layout Change to " + layoutPath + " failed. Exception raised was: " + ex.Message), LogType.Error.ToString());
- _isExpired = true;
-
+
ShowSplashScreen();
// In 10 seconds fire the next layout?
@@ -465,6 +504,9 @@ private void ChangeToNextLayout(string layoutPath)
// Start the timer
timer.Start();
}
+
+ // We have finished changing the layout
+ _changingLayout = false;
}
///
@@ -800,28 +842,42 @@ private static ImageCodecInfo GetEncoderInfo(string mimeType)
///
void temp_DurationElapsedEvent()
{
- Debug.WriteLine("Region Elapsed", "MainForm - DurationElapsedEvent");
+ Trace.WriteLine(new LogMessage("MainForm - DurationElapsedEvent", "Region Elapsed"), LogType.Audit.ToString());
- _isExpired = true;
+ // Are we already changing the layout?
+ if (_changingLayout)
+ {
+ Trace.WriteLine(new LogMessage("MainForm - DurationElapsedEvent", "Already Changing Layout"), LogType.Audit.ToString());
+ return;
+ }
+
+ bool isExpired = true;
// Check the other regions to see if they are also expired.
foreach (Region temp in _regions)
{
- if (!temp._hasExpired)
+ if (!temp.hasExpired())
{
- _isExpired = false;
+ isExpired = false;
+ break;
}
}
- if (_isExpired)
+ // If we are sure we have expired after checking all regions, then set the layout expired flag on them all
+ if (isExpired)
{
// Inform each region that the layout containing it has expired
foreach (Region temp in _regions)
{
- temp._layoutExpired = true;
+ temp.setLayoutExpired();
}
- System.Diagnostics.Debug.WriteLine("Region Expired - Next Region.", "MainForm - DurationElapsedEvent");
+ Trace.WriteLine(new LogMessage("MainForm - DurationElapsedEvent", "All Regions have expired. Raising a Next layout event."), LogType.Audit.ToString());
+
+ // We are changing the layout
+ _changingLayout = true;
+
+ // Yield and restart
_schedule.NextLayout();
}
}
@@ -833,27 +889,34 @@ private void DestroyLayout()
{
Debug.WriteLine("Destroying Layout", "MainForm - DestoryLayout");
- if (_regions == null) return;
+ if (_regions == null)
+ return;
- foreach (Region region in _regions)
+ lock (_regions)
{
- region.Clear();
-
- this.Controls.Remove(region);
-
- try
- {
- System.Diagnostics.Debug.WriteLine("Calling Dispose Region", "MainForm - DestoryLayout");
- region.Dispose();
- }
- catch (Exception e)
+ foreach (Region region in _regions)
{
- //do nothing (perhaps write to some error xml somewhere?)
- System.Diagnostics.Debug.WriteLine(e.Message);
+ try
+ {
+ // Remove the region from the list of controls
+ Controls.Remove(region);
+
+ // Clear the region
+ region.Clear();
+
+ Trace.WriteLine(new LogMessage("MainForm - DestoryLayout", "Calling Dispose on Region " + region.regionOptions.regionId), LogType.Audit.ToString());
+ region.Dispose();
+ }
+ catch (Exception e)
+ {
+ // If we can't dispose we should log to understand why
+ Trace.WriteLine(new LogMessage("MainForm - DestoryLayout", e.Message), LogType.Info.ToString());
+ }
}
+
+ _regions.Clear();
}
- _regions.Clear();
_regions = null;
}
diff --git a/Media/Flash.cs b/Media/Flash.cs
index ab4fdd17..032053e2 100644
--- a/Media/Flash.cs
+++ b/Media/Flash.cs
@@ -34,7 +34,8 @@ class Flash
private string _backgroundColor;
private string _backgroundTop;
private string _backgroundLeft;
-
+ private bool _disposed = false;
+
public Flash (RegionOptions options)
: base(options.width, options.height, options.top, options.left)
{
@@ -71,6 +72,10 @@ public Flash (RegionOptions options)
// Navigate to temp file
_webBrowser.Navigate(_tempHtml.Path);
+ Controls.Add(_webBrowser);
+
+ // Show the control
+ Show();
}
///
@@ -101,9 +106,12 @@ private void GenerateHeadHtml()
///
void _webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
- // We have navigated to the temporary file.
- Show();
- Controls.Add(_webBrowser);
+ base.StartTimer();
+
+ if (_disposed)
+ return;
+
+ _webBrowser.Visible = true;
}
///
@@ -112,6 +120,7 @@ void _webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEve
///
protected override void Dispose(bool disposing)
{
+ _disposed = true;
if (disposing)
{
// Remove the webbrowser control
diff --git a/Media/Media.cs b/Media/Media.cs
index 5d3525f3..0728e692 100644
--- a/Media/Media.cs
+++ b/Media/Media.cs
@@ -236,6 +236,7 @@ protected override void Dispose(bool disposing)
{
try
{
+ // Dispose of the Timer
if (_timer != null)
_timer.Dispose();
}
diff --git a/Media/Video.cs b/Media/Video.cs
index 7c96d9c4..7c47a3d1 100644
--- a/Media/Video.cs
+++ b/Media/Video.cs
@@ -54,8 +54,7 @@ public Video(RegionOptions options)
_videoPlayer.Location = new System.Drawing.Point(0, 0);
// Should we loop?
- if (options.Dictionary.Get("loop", "0") == "1" && _duration == 0)
- _videoPlayer.SetLooping(true);
+ _videoPlayer.SetLooping((options.Dictionary.Get("loop", "0") == "1" && _duration != 0));
// Should we mute?
_videoPlayer.SetMute((options.Dictionary.Get("mute", "0") == "1"));
@@ -129,6 +128,7 @@ void _videoPlayer_VideoEnd()
// Immediately hide the player
_videoPlayer.Hide();
+ // Set to expired
_expired = true;
}
}
@@ -148,13 +148,18 @@ protected override void Dispose(bool disposing)
{
try
{
- _videoPlayer.Hide();
+ // Stop and Clear
+ _videoPlayer.StopAndClear();
+
+ // Remove the control
Controls.Remove(_videoPlayer);
+
+ // Dispose of the Control
_videoPlayer.Dispose();
}
- catch
+ catch (Exception e)
{
-
+ Trace.WriteLine(new LogMessage("Video - Dispose", "Problem disposing of the Video Player. Ex = " + e.Message), LogType.Audit.ToString());
}
base.Dispose(disposing);
diff --git a/Media/VideoPlayer.Designer.cs b/Media/VideoPlayer.Designer.cs
index f979eb45..d6956d6e 100644
--- a/Media/VideoPlayer.Designer.cs
+++ b/Media/VideoPlayer.Designer.cs
@@ -59,5 +59,6 @@ private void InitializeComponent()
#endregion
private AxWMPLib.AxWindowsMediaPlayer axWindowsMediaPlayer1;
+
}
}
\ No newline at end of file
diff --git a/Media/VideoPlayer.cs b/Media/VideoPlayer.cs
index dc7003e3..fc6b3bc8 100644
--- a/Media/VideoPlayer.cs
+++ b/Media/VideoPlayer.cs
@@ -25,6 +25,7 @@
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
+using System.Runtime.InteropServices;
/// 09/06/12 Dan Changed to raise an event when the video is finished
/// 04/08/12 Dan Changed to raise an error event if one is raised from the control
@@ -41,6 +42,8 @@ public partial class VideoPlayer : Form
public delegate void VideoErrored();
public event VideoErrored VideoError;
+ private bool _looping = false;
+
public VideoPlayer()
{
InitializeComponent();
@@ -59,7 +62,7 @@ public void StartPlayer(string filePath)
axWindowsMediaPlayer1.uiMode = "none";
axWindowsMediaPlayer1.URL = filePath;
axWindowsMediaPlayer1.stretchToFit = true;
- axWindowsMediaPlayer1.windowlessVideo = true;
+ axWindowsMediaPlayer1.windowlessVideo = false;
axWindowsMediaPlayer1.PlayStateChange += new AxWMPLib._WMPOCXEvents_PlayStateChangeEventHandler(axWMP_PlayStateChange);
axWindowsMediaPlayer1.ErrorEvent += new EventHandler(axWindowsMediaPlayer1_ErrorEvent);
@@ -68,6 +71,7 @@ public void StartPlayer(string filePath)
public void SetLooping(bool looping)
{
axWindowsMediaPlayer1.settings.setMode("loop", looping);
+ _looping = looping;
}
public void SetMute(bool mute)
@@ -78,6 +82,40 @@ public void SetMute(bool mute)
axWindowsMediaPlayer1.settings.volume = 100;
}
+ public void StopAndClear()
+ {
+ try
+ {
+ GC.WaitForPendingFinalizers();
+ GC.Collect();
+
+ if (axWindowsMediaPlayer1 != null)
+ {
+ // Unbind events
+ axWindowsMediaPlayer1.PlayStateChange -= axWMP_PlayStateChange;
+ axWindowsMediaPlayer1.ErrorEvent -= axWindowsMediaPlayer1_ErrorEvent;
+
+ // Release resources
+ Marshal.FinalReleaseComObject(axWindowsMediaPlayer1.currentMedia);
+ axWindowsMediaPlayer1.URL = null;
+ axWindowsMediaPlayer1.close();
+
+ // Remove the WMP control
+ Controls.Remove(axWindowsMediaPlayer1);
+
+ // Close this form
+ Close();
+
+ //axWindowsMediaPlayer1.Dispose();
+ axWindowsMediaPlayer1 = null;
+ }
+ }
+ catch (AccessViolationException)
+ {
+
+ }
+ }
+
void axWindowsMediaPlayer1_ErrorEvent(object sender, EventArgs e)
{
// Get the error for logging
@@ -91,20 +129,37 @@ void axWindowsMediaPlayer1_ErrorEvent(object sender, EventArgs e)
error = "Unknown Error";
}
- Trace.WriteLine(new LogMessage("VideoPlayer - ErrorEvent", error), LogType.Error.ToString());
+ Trace.WriteLine(new LogMessage("VideoPlayer - ErrorEvent", axWindowsMediaPlayer1.URL + ". Ex = " + error), LogType.Error.ToString());
// Raise the event
- VideoError();
+ if (VideoError == null)
+ {
+ // The parent form has been ditached and disposed
+ StopAndClear();
+ }
+ else
+ {
+ VideoError();
+ }
}
void axWMP_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
- if (e.newState == 8)
+ if (e.newState == 8 && !_looping)
{
// indicate we are stopped
_finished = true;
- VideoEnd();
+ // Raise the event
+ if (VideoEnd == null)
+ {
+ // The parent form has been ditached and disposed
+ StopAndClear();
+ }
+ else
+ {
+ VideoEnd();
+ }
}
}
diff --git a/Media/VideoPlayer.resx b/Media/VideoPlayer.resx
index f30319b7..2769d211 100644
--- a/Media/VideoPlayer.resx
+++ b/Media/VideoPlayer.resx
@@ -112,14 +112,14 @@
2.0
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj0yLjAuMC4w
+ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACFTeXN0
ZW0uV2luZG93cy5Gb3Jtcy5BeEhvc3QrU3RhdGUBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAuQAAAAIB
AAAAAQAAAAAAAAAAAAAAAKQAAAAAAwAACAACAAAAAAAFAAAAAAAAAPA/AwAAAAAABQAAAAAAAAAAAAgA
diff --git a/Program.cs b/Program.cs
index 736dfc55..c5779161 100644
--- a/Program.cs
+++ b/Program.cs
@@ -1,6 +1,6 @@
/*
* Xibo - Digitial Signage - http://www.xibo.org.uk
- * Copyright (C) 2006-2012 Daniel Garner and James Packer
+ * Copyright (C) 2006-2015 Daniel Garner and the Xibo Developers
*
* This file is part of Xibo.
*
@@ -24,9 +24,6 @@
using System.Diagnostics;
using Xilium.CefGlue;
-// 17/08/2012 Dan Set process priority to RealTime
-// 21/08/2012 Dan Only enable visual styles for Options Form
-
namespace XiboClient
{
static class Program
@@ -37,35 +34,39 @@ static class Program
[STAThread]
static int Main(string[] args)
{
- try
- {
- CefRuntime.Load();
- }
- catch (DllNotFoundException ex)
- {
- MessageBox.Show(ex.Message, "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
- return 1;
- }
- catch (CefRuntimeException ex)
+ // Do we need to initialise CEF?
+ if (ApplicationSettings.Default.UseCefWebBrowser)
{
- MessageBox.Show(ex.Message, "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
- return 2;
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.ToString(), "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
- return 3;
- }
+ try
+ {
+ CefRuntime.Load();
+ }
+ catch (DllNotFoundException ex)
+ {
+ MessageBox.Show(ex.Message, "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ return 1;
+ }
+ catch (CefRuntimeException ex)
+ {
+ MessageBox.Show(ex.Message, "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ return 2;
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show(ex.ToString(), "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ return 3;
+ }
- var settings = new CefSettings();
- settings.MultiThreadedMessageLoop = true;
- settings.SingleProcess = false;
- settings.LogSeverity = CefLogSeverity.Disable;
- settings.LogFile = "cef.log";
- settings.ResourcesDirPath = System.IO.Path.GetDirectoryName(new Uri(System.Reflection.Assembly.GetEntryAssembly().CodeBase).LocalPath);
- settings.RemoteDebuggingPort = 20480;
+ var settings = new CefSettings();
+ settings.MultiThreadedMessageLoop = true;
+ settings.SingleProcess = false;
+ settings.LogSeverity = CefLogSeverity.Disable;
+ settings.LogFile = "cef.log";
+ settings.ResourcesDirPath = System.IO.Path.GetDirectoryName(new Uri(System.Reflection.Assembly.GetEntryAssembly().CodeBase).LocalPath);
+ settings.RemoteDebuggingPort = 20480;
- CefRuntime.Initialize(new CefMainArgs(args), settings, null, IntPtr.Zero);
+ CefRuntime.Initialize(new CefMainArgs(args), settings, null, IntPtr.Zero);
+ }
// Ensure our process has the highest priority
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.RealTime;
@@ -130,7 +131,9 @@ static int Main(string[] args)
Trace.WriteLine(new LogMessage("Main", "Application Finished"), LogType.Info.ToString());
Trace.Flush();
- CefRuntime.Shutdown();
+ if (ApplicationSettings.Default.UseCefWebBrowser)
+ CefRuntime.Shutdown();
+
return 0;
}
@@ -182,7 +185,9 @@ static void HandleUnhandledException(Object o)
// TODO: Can we just restart the application?
// Shutdown the application
- CefRuntime.Shutdown();
+ if (ApplicationSettings.Default.UseCefWebBrowser)
+ CefRuntime.Shutdown();
+
Environment.Exit(1);
}
diff --git a/XiboClient.csproj b/XiboClient.csproj
index 38179d02..5eeaac3c 100644
--- a/XiboClient.csproj
+++ b/XiboClient.csproj
@@ -301,7 +301,6 @@
-