real async plugin loading

This commit is contained in:
Paddy Xu
2017-06-04 17:26:07 +03:00
parent 86733a4d3d
commit 8bfedfc21d
4 changed files with 55 additions and 63 deletions

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Windows.Forms; using System.Windows.Forms;
using System.Windows.Threading;
namespace QuickLook namespace QuickLook
{ {
@@ -25,7 +26,8 @@ namespace QuickLook
if (e.Modifiers != Keys.None) if (e.Modifiers != Keys.None)
return; return;
ViewWindowManager.GetInstance().InvokeRoutine(e); Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => ViewWindowManager.GetInstance().InvokeRoutine(e)),
DispatcherPriority.ApplicationIdle);
} }
private void InstallKeyHook(KeyEventHandler handler) private void InstallKeyHook(KeyEventHandler handler)

View File

@@ -16,9 +16,6 @@ namespace QuickLook
/// </summary> /// </summary>
public partial class MainWindowTransparent : Window public partial class MainWindowTransparent : Window
{ {
private string _path = string.Empty;
private IViewer _plugin;
internal MainWindowTransparent() internal MainWindowTransparent()
{ {
// this object should be initialized before loading UI components, because many of which are binding to it. // this object should be initialized before loading UI components, because many of which are binding to it.
@@ -43,18 +40,21 @@ namespace QuickLook
ViewWindowManager.GetInstance().RunAndClosePreview(); ViewWindowManager.GetInstance().RunAndClosePreview();
} }
public string PreviewPath { get; private set; }
public IViewer Plugin { get; private set; }
public ContextObject ContextObject { get; private set; } public ContextObject ContextObject { get; private set; }
internal void RunAndHide() internal void RunAndHide()
{ {
if (string.IsNullOrEmpty(_path)) if (string.IsNullOrEmpty(PreviewPath))
return; return;
try try
{ {
Process.Start(new ProcessStartInfo(_path) Process.Start(new ProcessStartInfo(PreviewPath)
{ {
WorkingDirectory = Path.GetDirectoryName(_path) WorkingDirectory = Path.GetDirectoryName(PreviewPath)
}); });
} }
catch (Exception e) catch (Exception e)
@@ -96,21 +96,21 @@ namespace QuickLook
ContextObject.Reset(); ContextObject.Reset();
_plugin?.Cleanup(); Plugin?.Cleanup();
_plugin = null; Plugin = null;
ProcessHelper.PerformAggressiveGC(); ProcessHelper.PerformAggressiveGC();
} }
internal void BeginShow(IViewer matchedPlugin, string path) internal void BeginShow(IViewer matchedPlugin, string path, Action<ExceptionDispatchInfo> exceptionHandler)
{ {
_path = path; PreviewPath = path;
_plugin = matchedPlugin; Plugin = matchedPlugin;
ContextObject.ViewerWindow = this; ContextObject.ViewerWindow = this;
// get window size before showing it // get window size before showing it
_plugin.Prepare(path, ContextObject); Plugin.Prepare(path, ContextObject);
SetOpenWithButtonAndPath(); SetOpenWithButtonAndPath();
@@ -129,31 +129,27 @@ namespace QuickLook
//WindowHelper.SetActivate(new WindowInteropHelper(this), ContextObject.CanFocus); //WindowHelper.SetActivate(new WindowInteropHelper(this), ContextObject.CanFocus);
// load plugin, do not block UI // load plugin, do not block UI
Exception thrown = null;
Dispatcher.BeginInvoke(new Action(() => Dispatcher.BeginInvoke(new Action(() =>
{ {
try try
{ {
_plugin.View(path, ContextObject); Plugin.View(path, ContextObject);
} }
catch (Exception e) catch (Exception e)
{ {
thrown = e; exceptionHandler(ExceptionDispatchInfo.Capture(e));
} }
}), }),
DispatcherPriority.Render).Wait(); DispatcherPriority.Input);
if (thrown != null)
ExceptionDispatchInfo.Capture(thrown).Throw();
} }
private void SetOpenWithButtonAndPath() private void SetOpenWithButtonAndPath()
{ {
var isExe = FileHelper.GetAssocApplication(_path, out string appFriendlyName); var isExe = FileHelper.GetAssocApplication(PreviewPath, out string appFriendlyName);
buttonOpenWith.Content = isExe == null buttonOpenWith.Content = isExe == null
? Directory.Exists(_path) ? Directory.Exists(PreviewPath)
? $"Browse “{Path.GetFileName(_path)}”" ? $"Browse “{Path.GetFileName(PreviewPath)}”"
: "Open..." : "Open..."
: isExe == true : isExe == true
? $"Run “{appFriendlyName}”" ? $"Run “{appFriendlyName}”"

View File

@@ -4,7 +4,6 @@ using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks;
using QuickLook.ExtensionMethods; using QuickLook.ExtensionMethods;
using QuickLook.Plugin; using QuickLook.Plugin;
using QuickLook.Plugin.InfoPanel; using QuickLook.Plugin.InfoPanel;

View File

@@ -4,6 +4,7 @@ using System.IO;
using System.Runtime.ExceptionServices; using System.Runtime.ExceptionServices;
using System.Windows; using System.Windows;
using System.Windows.Forms; using System.Windows.Forms;
using System.Windows.Threading;
using QuickLook.Helpers; using QuickLook.Helpers;
using QuickLook.Plugin; using QuickLook.Plugin;
@@ -123,8 +124,8 @@ namespace QuickLook
private void SwitchPreviewRemoteInvoke(HeartbeatEventArgs e) private void SwitchPreviewRemoteInvoke(HeartbeatEventArgs e)
{ {
// sleep for 1.5s // sleep for 0.6s
if (e.InvokeTick - _lastSwitchTick < 1.5 * TimeSpan.TicksPerSecond) if (e.InvokeTick - _lastSwitchTick < 0.6 * TimeSpan.TicksPerSecond)
return; return;
if (e.FocusedFile == _path) if (e.FocusedFile == _path)
@@ -135,7 +136,7 @@ namespace QuickLook
if (string.IsNullOrEmpty(e.FocusedFile)) if (string.IsNullOrEmpty(e.FocusedFile))
return; return;
_currentMainWindow?.Dispatcher.Invoke(() => SwitchPreview()); _currentMainWindow?.Dispatcher.BeginInvoke(new Action(SwitchPreview), DispatcherPriority.ApplicationIdle);
} }
private void RunFocusMonitor() private void RunFocusMonitor()
@@ -158,59 +159,53 @@ namespace QuickLook
internal bool InvokeViewer(string path = null) internal bool InvokeViewer(string path = null)
{ {
if (path == null) if (path != null)
path = _path; _path = path;
if (string.IsNullOrEmpty(path)) if (string.IsNullOrEmpty(_path))
return false; return false;
if (!Directory.Exists(path) && !File.Exists(path)) if (!Directory.Exists(_path) && !File.Exists(_path))
return false; return false;
RunFocusMonitor(); RunFocusMonitor();
var matchedPlugin = PluginManager.GetInstance().FindMatch(path); var matchedPlugin = PluginManager.GetInstance().FindMatch(_path);
BeginShowNewWindow(matchedPlugin, path); BeginShowNewWindow(matchedPlugin);
return true; return true;
} }
private void BeginShowNewWindow(IViewer matchedPlugin, string path) private void BeginShowNewWindow(IViewer matchedPlugin)
{ {
try _currentMainWindow.UnloadPlugin();
{
_currentMainWindow.UnloadPlugin();
// switch window // switch window
var oldWindow = _currentMainWindow; var oldWindow = _currentMainWindow;
_currentMainWindow = matchedPlugin.AllowsTransparency _currentMainWindow = matchedPlugin.AllowsTransparency
? _viewWindowTransparentTransparent ? _viewWindowTransparentTransparent
: _viewWindowNoTransparent; : _viewWindowNoTransparent;
if (!ReferenceEquals(oldWindow, _currentMainWindow)) if (!ReferenceEquals(oldWindow, _currentMainWindow))
oldWindow.BeginHide(); oldWindow.BeginHide();
_currentMainWindow.BeginShow(matchedPlugin, path); _currentMainWindow.BeginShow(matchedPlugin, _path, CurrentPluginFailed);
} }
catch (Exception e) // if current plugin failed, switch to default one.
{
_currentMainWindow.BeginHide();
TrayIconManager.GetInstance().ShowNotification("", $"Failed to preview {Path.GetFileName(path)}", true); private void CurrentPluginFailed(ExceptionDispatchInfo e)
{
var plugin = _currentMainWindow.Plugin.GetType();
Debug.WriteLine(e.ToString()); _currentMainWindow.BeginHide();
Debug.WriteLine(e.StackTrace);
if (matchedPlugin != PluginManager.GetInstance().DefaultPlugin) TrayIconManager.GetInstance().ShowNotification("", $"Failed to preview {Path.GetFileName(_path)}", true);
{
matchedPlugin.Cleanup(); Debug.WriteLine(e.ToString());
matchedPlugin = PluginManager.GetInstance().DefaultPlugin; Debug.WriteLine(e.SourceException.StackTrace);
BeginShowNewWindow(matchedPlugin, path);
} if (plugin != PluginManager.GetInstance().DefaultPlugin.GetType())
else BeginShowNewWindow(PluginManager.GetInstance().DefaultPlugin);
{ else
ExceptionDispatchInfo.Capture(e).Throw(); e.Throw();
}
}
} }
internal static ViewWindowManager GetInstance() internal static ViewWindowManager GetInstance()