From 659ff866e119a6968c50113366156b63210118d0 Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Sat, 5 Jul 2014 23:10:34 +0800 Subject: [PATCH] Add Executable Plugin Loader --- Wox.Plugin.SystemPlugins/CMD/CMD.cs | 4 +- .../ThirdpartyPluginIndicator.cs | 11 +- .../WebSearch/WebSearchPlugin.cs | 4 +- Wox.Plugin/AllowedLanguage.cs | 9 +- Wox.Plugin/IPublicAPI.cs | 38 + Wox.Plugin/PluginInitContext.cs | 92 +- Wox.Plugin/Result.cs | 3 +- Wox.Plugin/Wox.Plugin.csproj | 1 + Wox/Commands/PluginCommand.cs | 29 +- Wox/Commands/SystemCommand.cs | 15 +- Wox/MainWindow.xaml.cs | 916 ++++++++++-------- Wox/PluginLoader/ExecutablePluginLoader.cs | 29 + Wox/PluginLoader/ExecutablePluginWrapper.cs | 72 ++ Wox/PluginLoader/Plugins.cs | 128 +-- Wox/RPC/JsonPRCModel.cs | 17 + Wox/RPC/JsonRPC.cs | 20 + Wox/Wox.csproj | 4 + 17 files changed, 850 insertions(+), 542 deletions(-) create mode 100644 Wox.Plugin/IPublicAPI.cs create mode 100644 Wox/PluginLoader/ExecutablePluginLoader.cs create mode 100644 Wox/PluginLoader/ExecutablePluginWrapper.cs create mode 100644 Wox/RPC/JsonPRCModel.cs create mode 100644 Wox/RPC/JsonRPC.cs diff --git a/Wox.Plugin.SystemPlugins/CMD/CMD.cs b/Wox.Plugin.SystemPlugins/CMD/CMD.cs index c205e3dca4..9d112aa1e3 100644 --- a/Wox.Plugin.SystemPlugins/CMD/CMD.cs +++ b/Wox.Plugin.SystemPlugins/CMD/CMD.cs @@ -59,7 +59,7 @@ namespace Wox.Plugin.SystemPlugins.CMD } catch (Exception) { } - context.PushResults(query, new List() { result }); + context.API.PushResults(query,context.CurrentPluginMetadata, new List() { result }); pushedResults.Add(result); IEnumerable history = CMDStorage.Instance.CMDHistory.Where(o => o.Key.Contains(cmd)) @@ -95,7 +95,7 @@ namespace Wox.Plugin.SystemPlugins.CMD return ret; }).Where(o => o != null).Take(4); - context.PushResults(query, history.ToList()); + context.API.PushResults(query,context.CurrentPluginMetadata,history.ToList()); pushedResults.AddRange(history); try diff --git a/Wox.Plugin.SystemPlugins/ThirdpartyPluginIndicator.cs b/Wox.Plugin.SystemPlugins/ThirdpartyPluginIndicator.cs index b5c817bda8..495a2c28ff 100644 --- a/Wox.Plugin.SystemPlugins/ThirdpartyPluginIndicator.cs +++ b/Wox.Plugin.SystemPlugins/ThirdpartyPluginIndicator.cs @@ -11,11 +11,13 @@ namespace Wox.Plugin.SystemPlugins public class ThirdpartyPluginIndicator : BaseSystemPlugin { private List allPlugins = new List(); - private Action changeQuery; + private PluginInitContext context; protected override List QueryInternal(Query query) { List results = new List(); + if(allPlugins.Count == 0) allPlugins = context.API.GetAllPlugins(); + foreach (PluginMetadata metadata in allPlugins.Select(o => o.Metadata)) { @@ -36,7 +38,7 @@ namespace Wox.Plugin.SystemPlugins IcoPath = "Images/work.png", Action = (c) => { - changeQuery(metadataCopy.ActionKeyword + " "); + context.ChangeQuery(metadataCopy.ActionKeyword + " "); return false; }, }; @@ -52,7 +54,7 @@ namespace Wox.Plugin.SystemPlugins IcoPath = "Images/work.png", Action = (c) => { - changeQuery(n.ActionWord + " "); + context.ChangeQuery(n.ActionWord + " "); return false; } })); @@ -62,8 +64,7 @@ namespace Wox.Plugin.SystemPlugins protected override void InitInternal(PluginInitContext context) { - allPlugins = context.Plugins; - changeQuery = context.ChangeQuery; + this.context = context; } diff --git a/Wox.Plugin.SystemPlugins/WebSearch/WebSearchPlugin.cs b/Wox.Plugin.SystemPlugins/WebSearch/WebSearchPlugin.cs index e2c69c47f3..b7afa08dd2 100644 --- a/Wox.Plugin.SystemPlugins/WebSearch/WebSearchPlugin.cs +++ b/Wox.Plugin.SystemPlugins/WebSearch/WebSearchPlugin.cs @@ -32,7 +32,7 @@ namespace Wox.Plugin.SystemPlugins title = subtitle; subtitle = null; } - context.PushResults(query, new List() + context.API.PushResults(query,context.CurrentPluginMetadata, new List() { new Result() { @@ -54,7 +54,7 @@ namespace Wox.Plugin.SystemPlugins var result = sugg.GetSuggestions(keyword); if (result != null) { - context.PushResults(query, result.Select(o => new Result() + context.API.PushResults(query,context.CurrentPluginMetadata, result.Select(o => new Result() { Title = o, SubTitle = subtitle, diff --git a/Wox.Plugin/AllowedLanguage.cs b/Wox.Plugin/AllowedLanguage.cs index c6d0fa805b..32262b48f2 100644 --- a/Wox.Plugin/AllowedLanguage.cs +++ b/Wox.Plugin/AllowedLanguage.cs @@ -17,9 +17,16 @@ namespace Wox.Plugin get { return "csharp"; } } + public static string ExecutableFile + { + get { return "ExecutableFile"; } + } + public static bool IsAllowed(string language) { - return language.ToUpper() == Python.ToUpper() || language.ToUpper() == CSharp.ToUpper(); + return language.ToUpper() == Python.ToUpper() + || language.ToUpper() == CSharp.ToUpper() + || language.ToUpper() == ExecutableFile.ToUpper(); } } } \ No newline at end of file diff --git a/Wox.Plugin/IPublicAPI.cs b/Wox.Plugin/IPublicAPI.cs new file mode 100644 index 0000000000..eb3b8fffba --- /dev/null +++ b/Wox.Plugin/IPublicAPI.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Windows.Documents; + +namespace Wox.Plugin +{ + public interface IPublicAPI + { + + void PushResults(Query query,PluginMetadata plugin, List results); + + bool ShellRun(string cmd); + + void ChangeQuery(string query, bool requery = false); + + void CloseApp(); + + void HideApp(); + + void ShowApp(); + + void ShowMsg(string title, string subTitle, string iconPath); + + void OpenSettingDialog(); + + void ShowCurrentResultItemTooltip(string tooltip); + + void StartLoadingBar(); + + void StopLoadingBar(); + + void InstallPlugin(string path); + + void ReloadPlugins(); + + List GetAllPlugins(); + } +} diff --git a/Wox.Plugin/PluginInitContext.cs b/Wox.Plugin/PluginInitContext.cs index 68be7a58f1..f38b1c1c70 100644 --- a/Wox.Plugin/PluginInitContext.cs +++ b/Wox.Plugin/PluginInitContext.cs @@ -7,31 +7,87 @@ namespace Wox.Plugin { public class PluginInitContext { - public List Plugins { get; set; } public PluginMetadata CurrentPluginMetadata { get; set; } - - public Action ChangeQuery { get; set; } - public Action CloseApp { get; set; } - public Action HideApp { get; set; } - public Action ShowApp { get; set; } - public Action ShowMsg { get; set; } - public Action OpenSettingDialog { get; set; } - - public Action ShowCurrentResultItemTooltip { get; set; } - /// - /// reload all plugins + /// Public APIs for plugin invocation /// - public Action ReloadPlugins { get; set; } + public IPublicAPI API { get; set; } - public Action InstallPlugin { get; set; } + #region Legacy APIs - public Action StartLoadingBar { get; set; } - public Action StopLoadingBar { get; set; } + [Obsolete("This method has been obsoleted, use API.ShellRun instead")] + public bool ShellRun(string cmd) + { + return API.ShellRun(cmd); + } - public Func ShellRun { get; set; } + [Obsolete("This method has been obsoleted, use API.OpenSettingDialog instead")] + public void ChangeQuery(string query, bool requery = false) + { + API.ChangeQuery(query, requery); + } - public Action> PushResults { get; set; } + [Obsolete("This method has been obsoleted, use API.CloseApp instead")] + public void CloseApp() + { + API.CloseApp(); + } + + [Obsolete("This method has been obsoleted, use API.HideApp instead")] + public void HideApp() + { + API.HideApp(); + } + + [Obsolete("This method has been obsoleted, use API.ShowApp instead")] + public void ShowApp() + { + API.ShowApp(); + } + + [Obsolete("This method has been obsoleted, use API.OpenSettingDialog instead")] + public void ShowMsg(string title, string subTitle, string iconPath) + { + API.ShowMsg(title, subTitle, iconPath); + } + + [Obsolete("This method has been obsoleted, use API.OpenSettingDialog instead")] + public void OpenSettingDialog() + { + API.OpenSettingDialog(); + } + + [Obsolete("This method has been obsoleted, use API.ShowCurrentResultItemTooltip instead")] + public void ShowCurrentResultItemTooltip(string tooltip) + { + API.ShowCurrentResultItemTooltip(tooltip); + } + + [Obsolete("This method has been obsoleted, use API.StartLoadingBar instead")] + public void StartLoadingBar() + { + API.StartLoadingBar(); + } + + [Obsolete("This method has been obsoleted, use API.StopLoadingBar instead")] + public void StopLoadingBar() + { + API.StopLoadingBar(); + } + + [Obsolete("This method has been obsoleted, use API.InstallPlugin instead")] + public void InstallPlugin(string path) + { + API.InstallPlugin(path); + } + + [Obsolete("This method has been obsoleted, use API.ReloadPlugins instead")] + public void ReloadPlugins() + { + API.ReloadPlugins(); + } + + #endregion } } diff --git a/Wox.Plugin/Result.cs b/Wox.Plugin/Result.cs index fa70cc99a9..f0c7fd4460 100644 --- a/Wox.Plugin/Result.cs +++ b/Wox.Plugin/Result.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; namespace Wox.Plugin { + public class Result { public string Title { get; set; } public string SubTitle { get; set; } @@ -41,7 +42,6 @@ namespace Wox.Plugin { return Title + SubTitle; } - public Result() { } @@ -52,6 +52,5 @@ namespace Wox.Plugin { this.SubTitle = SubTitle; } - } } \ No newline at end of file diff --git a/Wox.Plugin/Wox.Plugin.csproj b/Wox.Plugin/Wox.Plugin.csproj index e6a31c09cc..558dc86573 100644 --- a/Wox.Plugin/Wox.Plugin.csproj +++ b/Wox.Plugin/Wox.Plugin.csproj @@ -46,6 +46,7 @@ + diff --git a/Wox/Commands/PluginCommand.cs b/Wox/Commands/PluginCommand.cs index 1c25e5d5ad..388db8ecb0 100644 --- a/Wox/Commands/PluginCommand.cs +++ b/Wox/Commands/PluginCommand.cs @@ -15,40 +15,29 @@ namespace Wox.Commands private string currentPythonModulePath = string.Empty; private IntPtr GIL; - public override void Dispatch(Query q) + public override void Dispatch(Query query) { - PluginPair thirdPlugin = Plugins.AllPlugins.FirstOrDefault(o => o.Metadata.ActionKeyword == q.ActionName); + PluginPair thirdPlugin = Plugins.AllPlugins.FirstOrDefault(o => o.Metadata.ActionKeyword == query.ActionName); if (thirdPlugin != null && !string.IsNullOrEmpty(thirdPlugin.Metadata.ActionKeyword)) { var customizedPluginConfig = UserSettingStorage.Instance.CustomizedPluginConfigs.FirstOrDefault(o => o.ID == thirdPlugin.Metadata.ID); if (customizedPluginConfig != null && customizedPluginConfig.Disabled) { + //need to stop the loading animation UpdateResultView(null); return; } - if (thirdPlugin.Metadata.Language == AllowedLanguage.Python) - { - SwitchPythonEnv(thirdPlugin); - } + //if (thirdPlugin.Metadata.Language == AllowedLanguage.Python) + //{ + // SwitchPythonEnv(thirdPlugin); + //} ThreadPool.QueueUserWorkItem(t => { try { - thirdPlugin.InitContext.PushResults = (qu, r) => - { - if (r != null) - { - r.ForEach(o => - { - o.PluginDirectory = thirdPlugin.Metadata.PluginDirecotry; - o.OriginQuery = qu; - }); - UpdateResultView(r); - } - }; - List results = thirdPlugin.Plugin.Query(q) ?? new List(); - thirdPlugin.InitContext.PushResults(q, results); + List results = thirdPlugin.Plugin.Query(query) ?? new List(); + App.Window.PushResults(query,thirdPlugin.Metadata,results); } catch (Exception queryException) { diff --git a/Wox/Commands/SystemCommand.cs b/Wox/Commands/SystemCommand.cs index e38a5ca12b..e3eee7fb6c 100644 --- a/Wox/Commands/SystemCommand.cs +++ b/Wox/Commands/SystemCommand.cs @@ -19,19 +19,10 @@ namespace Wox.Commands ThreadPool.QueueUserWorkItem(state => { - pair1.InitContext.PushResults = (q, r) => - { - foreach (Result result in r) - { - result.PluginDirectory = pair1.Metadata.PluginDirecotry; - result.OriginQuery = q; - result.AutoAjustScore = true; - } - UpdateResultView(r); - }; - List results = pair1.Plugin.Query(query); - pair1.InitContext.PushResults(query, results); + results.ForEach(o=> { o.AutoAjustScore = true; }); + + App.Window.PushResults(query,pair1.Metadata,results); }); } } diff --git a/Wox/MainWindow.xaml.cs b/Wox/MainWindow.xaml.cs index c83d82073d..e410307f3e 100644 --- a/Wox/MainWindow.xaml.cs +++ b/Wox/MainWindow.xaml.cs @@ -35,429 +35,538 @@ using Rectangle = System.Drawing.Rectangle; using TextBox = System.Windows.Controls.TextBox; using ToolTip = System.Windows.Controls.ToolTip; -namespace Wox { - public partial class MainWindow { +namespace Wox +{ + public partial class MainWindow : IPublicAPI + { - #region Properties + #region Properties private static readonly object locker = new object(); public static bool initialized = false; private static readonly List waitShowResultList = new List(); - private readonly GlobalHotkey globalHotkey = new GlobalHotkey(); - private readonly KeyboardSimulator keyboardSimulator = new KeyboardSimulator(new InputSimulator()); - private readonly Storyboard progressBarStoryboard = new Storyboard(); - private bool WinRStroked; - private NotifyIcon notifyIcon; - private bool queryHasReturn; - private string lastQuery; - private ToolTip toolTip = new ToolTip(); + private readonly GlobalHotkey globalHotkey = new GlobalHotkey(); + private readonly KeyboardSimulator keyboardSimulator = new KeyboardSimulator(new InputSimulator()); + private readonly Storyboard progressBarStoryboard = new Storyboard(); + private bool WinRStroked; + private NotifyIcon notifyIcon; + private bool queryHasReturn; + private string lastQuery; + private ToolTip toolTip = new ToolTip(); - private bool isCMDMode = false; - private bool ignoreTextChange = false; - #endregion + private bool isCMDMode = false; + private bool ignoreTextChange = false; + #endregion - #region Public API + #region Public API - public void ChangeQuery(string query, bool requery = false) { - tbQuery.Text = query; - tbQuery.CaretIndex = tbQuery.Text.Length; - if (requery) { - TextBoxBase_OnTextChanged(null, null); - } - } + public void ChangeQuery(string query, bool requery = false) + { + Dispatcher.Invoke(new Action(() => + { + tbQuery.Text = query; + tbQuery.CaretIndex = tbQuery.Text.Length; + if (requery) + { + TextBoxBase_OnTextChanged(null, null); + } + })); + } - public void CloseApp() { - notifyIcon.Visible = false; - Close(); - Environment.Exit(0); - } + public void CloseApp() + { + Dispatcher.Invoke(new Action(() => + { + notifyIcon.Visible = false; + Close(); + Environment.Exit(0); + })); + } - public void HideApp() { - HideWox(); - } + public void HideApp() + { + Dispatcher.Invoke(new Action(HideWox)); + } - public void ShowApp() { - ShowWox(); - } + public void ShowApp() + { + Dispatcher.Invoke(new Action(() => ShowWox())); + } - public void ShowMsg(string title, string subTitle, string iconPath) { - var m = new Msg { Owner = GetWindow(this) }; - m.Show(title, subTitle, iconPath); - } + public void ShowMsg(string title, string subTitle, string iconPath) + { + Dispatcher.Invoke(new Action(() => + { + var m = new Msg {Owner = GetWindow(this)}; + m.Show(title, subTitle, iconPath); + })); + } - public void OpenSettingDialog() { - WindowOpener.Open(this); - } + public void OpenSettingDialog() + { + Dispatcher.Invoke(new Action(() => WindowOpener.Open(this))); + } - public void ShowCurrentResultItemTooltip(string text) { - toolTip.Content = text; - toolTip.IsOpen = true; - } + public void ShowCurrentResultItemTooltip(string text) + { + Dispatcher.Invoke(new Action(() => + { + toolTip.Content = text; + toolTip.IsOpen = true; + })); + } - public void StartLoadingBar() { - Dispatcher.Invoke(new Action(StartProgress)); - } + public void StartLoadingBar() + { + Dispatcher.Invoke(new Action(StartProgress)); + } - public void StopLoadingBar() { - Dispatcher.Invoke(new Action(StopProgress)); - } + public void StopLoadingBar() + { + Dispatcher.Invoke(new Action(StopProgress)); + } - #endregion + public void InstallPlugin(string path) + { + Dispatcher.Invoke(new Action(() => PluginInstaller.Install(path))); + } - public MainWindow() { - InitializeComponent(); + public void ReloadPlugins() + { + Dispatcher.Invoke(new Action(Plugins.Init)); + } - if (UserSettingStorage.Instance.OpacityMode == OpacityMode.LayeredWindow) - this.AllowsTransparency = true; + public List GetAllPlugins() + { + return Plugins.AllPlugins; + } - System.Net.WebRequest.RegisterPrefix("data", new DataWebRequestFactory()); + public void PushResults(Query query, PluginMetadata plugin, List results) + { + results.ForEach(o => + { + o.PluginDirectory = plugin.PluginDirecotry; + o.OriginQuery = query; + }); + OnUpdateResultView(results); + } - progressBar.ToolTip = toolTip; - InitialTray(); - resultCtrl.OnMouseClickItem += AcceptSelect; + #endregion - ThreadPool.SetMaxThreads(30, 10); - try { - SetTheme(UserSettingStorage.Instance.Theme); - } - catch (Exception) { - SetTheme(UserSettingStorage.Instance.Theme = "Dark"); - } - SetHotkey(UserSettingStorage.Instance.Hotkey, OnHotkey); - SetCustomPluginHotkey(); + public MainWindow() + { + InitializeComponent(); - globalHotkey.hookedKeyboardCallback += KListener_hookedKeyboardCallback; + if (UserSettingStorage.Instance.OpacityMode == OpacityMode.LayeredWindow) + this.AllowsTransparency = true; - this.Closing += MainWindow_Closing; - } + System.Net.WebRequest.RegisterPrefix("data", new DataWebRequestFactory()); - void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) { - UserSettingStorage.Instance.WindowLeft = Left; - UserSettingStorage.Instance.WindowTop = Top; - UserSettingStorage.Instance.Save(); - this.HideWox(); - e.Cancel = true; - } + progressBar.ToolTip = toolTip; + InitialTray(); + resultCtrl.OnMouseClickItem += AcceptSelect; - private void MainWindow_OnLoaded(object sender, RoutedEventArgs e) { - if (UserSettingStorage.Instance.WindowLeft == 0 - && UserSettingStorage.Instance.WindowTop == 0) - { - Left = UserSettingStorage.Instance.WindowLeft - = (SystemParameters.PrimaryScreenWidth - ActualWidth) / 2; - Top = UserSettingStorage.Instance.WindowTop - = (SystemParameters.PrimaryScreenHeight - ActualHeight) / 5; - } - else { - Left = UserSettingStorage.Instance.WindowLeft; - Top = UserSettingStorage.Instance.WindowTop; - } + ThreadPool.SetMaxThreads(30, 10); + try + { + SetTheme(UserSettingStorage.Instance.Theme); + } + catch (Exception) + { + SetTheme(UserSettingStorage.Instance.Theme = "Dark"); + } - Plugins.Init(); + SetHotkey(UserSettingStorage.Instance.Hotkey, OnHotkey); + SetCustomPluginHotkey(); - InitProgressbarAnimation(); + globalHotkey.hookedKeyboardCallback += KListener_hookedKeyboardCallback; - //only works for win7+ - if (UserSettingStorage.Instance.OpacityMode == OpacityMode.DWM) - DwmDropShadow.DropShadowToWindow(this); + this.Closing += MainWindow_Closing; + } - this.Background = Brushes.Transparent; - HwndSource.FromHwnd(new WindowInteropHelper(this).Handle).CompositionTarget.BackgroundColor = Color.FromArgb(0, 0, 0, 0); + void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) + { + UserSettingStorage.Instance.WindowLeft = Left; + UserSettingStorage.Instance.WindowTop = Top; + UserSettingStorage.Instance.Save(); + this.HideWox(); + e.Cancel = true; + } - WindowIntelopHelper.DisableControlBox(this); - } + private void MainWindow_OnLoaded(object sender, RoutedEventArgs e) + { + if (UserSettingStorage.Instance.WindowLeft == 0 + && UserSettingStorage.Instance.WindowTop == 0) + { + Left = UserSettingStorage.Instance.WindowLeft + = (SystemParameters.PrimaryScreenWidth - ActualWidth) / 2; + Top = UserSettingStorage.Instance.WindowTop + = (SystemParameters.PrimaryScreenHeight - ActualHeight) / 5; + } + else + { + Left = UserSettingStorage.Instance.WindowLeft; + Top = UserSettingStorage.Instance.WindowTop; + } - public void SetHotkey(string hotkeyStr, EventHandler action) { - var hotkey = new HotkeyModel(hotkeyStr); - try { - HotkeyManager.Current.AddOrReplace(hotkeyStr, hotkey.CharKey, hotkey.ModifierKeys, action); - } - catch (Exception) { - MessageBox.Show("Register hotkey: " + hotkeyStr + " failed."); - } - } + Plugins.Init(); - public void RemoveHotkey(string hotkeyStr) { - if (!string.IsNullOrEmpty(hotkeyStr)) { - HotkeyManager.Current.Remove(hotkeyStr); - } - } + InitProgressbarAnimation(); - private void SetCustomPluginHotkey() { - if (UserSettingStorage.Instance.CustomPluginHotkeys == null) return; - foreach (CustomPluginHotkey hotkey in UserSettingStorage.Instance.CustomPluginHotkeys) { - CustomPluginHotkey hotkey1 = hotkey; - SetHotkey(hotkey.Hotkey, delegate { - ShowApp(); - ChangeQuery(hotkey1.ActionKeyword, true); - }); - } - } + //only works for win7+ + if (UserSettingStorage.Instance.OpacityMode == OpacityMode.DWM) + DwmDropShadow.DropShadowToWindow(this); - private void OnHotkey(object sender, HotkeyEventArgs e) { - if (!IsVisible) { - ShowWox(); - } - else { - HideWox(); - } - e.Handled = true; - } + this.Background = Brushes.Transparent; + HwndSource.FromHwnd(new WindowInteropHelper(this).Handle).CompositionTarget.BackgroundColor = Color.FromArgb(0, 0, 0, 0); - private void InitProgressbarAnimation() { - var da = new DoubleAnimation(progressBar.X2, ActualWidth + 100, new Duration(new TimeSpan(0, 0, 0, 0, 1600))); - var da1 = new DoubleAnimation(progressBar.X1, ActualWidth, new Duration(new TimeSpan(0, 0, 0, 0, 1600))); - Storyboard.SetTargetProperty(da, new PropertyPath("(Line.X2)")); - Storyboard.SetTargetProperty(da1, new PropertyPath("(Line.X1)")); - progressBarStoryboard.Children.Add(da); - progressBarStoryboard.Children.Add(da1); - progressBarStoryboard.RepeatBehavior = RepeatBehavior.Forever; - progressBar.Visibility = Visibility.Hidden; - progressBar.BeginStoryboard(progressBarStoryboard); - } + WindowIntelopHelper.DisableControlBox(this); + } - private void InitialTray() { - notifyIcon = new NotifyIcon { Text = "Wox", Icon = Properties.Resources.app, Visible = true }; - notifyIcon.Click += (o, e) => ShowWox(); - var open = new MenuItem("Open"); - open.Click += (o, e) => ShowWox(); - var setting = new MenuItem("Setting"); - setting.Click += (o, e) => OpenSettingDialog(); - var exit = new MenuItem("Exit"); - exit.Click += (o, e) => CloseApp(); - MenuItem[] childen = { open, setting, exit }; - notifyIcon.ContextMenu = new ContextMenu(childen); - } + public void SetHotkey(string hotkeyStr, EventHandler action) + { + var hotkey = new HotkeyModel(hotkeyStr); + try + { + HotkeyManager.Current.AddOrReplace(hotkeyStr, hotkey.CharKey, hotkey.ModifierKeys, action); + } + catch (Exception) + { + MessageBox.Show("Register hotkey: " + hotkeyStr + " failed."); + } + } - private void TextBoxBase_OnTextChanged(object sender, TextChangedEventArgs e) { - if (ignoreTextChange) { ignoreTextChange = false; return; } + public void RemoveHotkey(string hotkeyStr) + { + if (!string.IsNullOrEmpty(hotkeyStr)) + { + HotkeyManager.Current.Remove(hotkeyStr); + } + } - lastQuery = tbQuery.Text; - toolTip.IsOpen = false; - resultCtrl.Dirty = true; - Dispatcher.DelayInvoke("UpdateSearch", - o => { - Dispatcher.DelayInvoke("ClearResults", i => { - // first try to use clear method inside resultCtrl, which is more closer to the add new results - // and this will not bring splash issues.After waiting 30ms, if there still no results added, we - // must clear the result. otherwise, it will be confused why the query changed, but the results - // didn't. - if (resultCtrl.Dirty) resultCtrl.Clear(); - }, TimeSpan.FromMilliseconds(100), null); + private void SetCustomPluginHotkey() + { + if (UserSettingStorage.Instance.CustomPluginHotkeys == null) return; + foreach (CustomPluginHotkey hotkey in UserSettingStorage.Instance.CustomPluginHotkeys) + { + CustomPluginHotkey hotkey1 = hotkey; + SetHotkey(hotkey.Hotkey, delegate + { + ShowApp(); + ChangeQuery(hotkey1.ActionKeyword, true); + }); + } + } + + private void OnHotkey(object sender, HotkeyEventArgs e) + { + if (!IsVisible) + { + ShowWox(); + } + else + { + HideWox(); + } + e.Handled = true; + } + + private void InitProgressbarAnimation() + { + var da = new DoubleAnimation(progressBar.X2, ActualWidth + 100, new Duration(new TimeSpan(0, 0, 0, 0, 1600))); + var da1 = new DoubleAnimation(progressBar.X1, ActualWidth, new Duration(new TimeSpan(0, 0, 0, 0, 1600))); + Storyboard.SetTargetProperty(da, new PropertyPath("(Line.X2)")); + Storyboard.SetTargetProperty(da1, new PropertyPath("(Line.X1)")); + progressBarStoryboard.Children.Add(da); + progressBarStoryboard.Children.Add(da1); + progressBarStoryboard.RepeatBehavior = RepeatBehavior.Forever; + progressBar.Visibility = Visibility.Hidden; + progressBar.BeginStoryboard(progressBarStoryboard); + } + + private void InitialTray() + { + notifyIcon = new NotifyIcon { Text = "Wox", Icon = Properties.Resources.app, Visible = true }; + notifyIcon.Click += (o, e) => ShowWox(); + var open = new MenuItem("Open"); + open.Click += (o, e) => ShowWox(); + var setting = new MenuItem("Setting"); + setting.Click += (o, e) => OpenSettingDialog(); + var exit = new MenuItem("Exit"); + exit.Click += (o, e) => CloseApp(); + MenuItem[] childen = { open, setting, exit }; + notifyIcon.ContextMenu = new ContextMenu(childen); + } + + private void TextBoxBase_OnTextChanged(object sender, TextChangedEventArgs e) + { + if (ignoreTextChange) { ignoreTextChange = false; return; } + + lastQuery = tbQuery.Text; + toolTip.IsOpen = false; + resultCtrl.Dirty = true; + Dispatcher.DelayInvoke("UpdateSearch", + o => + { + Dispatcher.DelayInvoke("ClearResults", i => + { + // first try to use clear method inside resultCtrl, which is more closer to the add new results + // and this will not bring splash issues.After waiting 30ms, if there still no results added, we + // must clear the result. otherwise, it will be confused why the query changed, but the results + // didn't. + if (resultCtrl.Dirty) resultCtrl.Clear(); + }, TimeSpan.FromMilliseconds(100), null); queryHasReturn = false; - var q = new Query(lastQuery); - CommandFactory.DispatchCommand(q); - if (Plugins.HitThirdpartyKeyword(q)) { - Dispatcher.DelayInvoke("ShowProgressbar", originQuery => { - if (!queryHasReturn && originQuery == lastQuery) { - StartProgress(); - } - }, TimeSpan.FromSeconds(0), lastQuery); - } - }, TimeSpan.FromMilliseconds((isCMDMode = tbQuery.Text.StartsWith(">")) ? 0 : 150)); - } + var q = new Query(lastQuery); + CommandFactory.DispatchCommand(q); + if (Plugins.HitThirdpartyKeyword(q)) + { + Dispatcher.DelayInvoke("ShowProgressbar", originQuery => + { + if (!queryHasReturn && originQuery == lastQuery) + { + StartProgress(); + } + }, TimeSpan.FromSeconds(0), lastQuery); + } + }, TimeSpan.FromMilliseconds((isCMDMode = tbQuery.Text.StartsWith(">")) ? 0 : 150)); + } - private void Border_OnMouseDown(object sender, MouseButtonEventArgs e) { - if (e.ChangedButton == MouseButton.Left) DragMove(); - } + private void Border_OnMouseDown(object sender, MouseButtonEventArgs e) + { + if (e.ChangedButton == MouseButton.Left) DragMove(); + } - private void StartProgress() { - progressBar.Visibility = Visibility.Visible; - } + private void StartProgress() + { + progressBar.Visibility = Visibility.Visible; + } - private void StopProgress() { - progressBar.Visibility = Visibility.Hidden; - } + private void StopProgress() + { + progressBar.Visibility = Visibility.Hidden; + } - private void HideWox() { - Hide(); - } + private void HideWox() + { + Hide(); + } - private void ShowWox(bool selectAll = true) { - if (!double.IsNaN(Left) && !double.IsNaN(Top)) { - var origScreen = Screen.FromRectangle(new Rectangle((int)Left, (int)Top, (int)ActualWidth, (int)ActualHeight)); - var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position); - var coordX = (Left - origScreen.WorkingArea.Left) / (origScreen.WorkingArea.Width - ActualWidth); - var coordY = (Top - origScreen.WorkingArea.Top) / (origScreen.WorkingArea.Height - ActualHeight); - Left = (screen.WorkingArea.Width - ActualWidth) * coordX + screen.WorkingArea.Left; - Top = (screen.WorkingArea.Height - ActualHeight) * coordY + screen.WorkingArea.Top; - } + private void ShowWox(bool selectAll = true) + { + if (!double.IsNaN(Left) && !double.IsNaN(Top)) + { + var origScreen = Screen.FromRectangle(new Rectangle((int)Left, (int)Top, (int)ActualWidth, (int)ActualHeight)); + var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position); + var coordX = (Left - origScreen.WorkingArea.Left) / (origScreen.WorkingArea.Width - ActualWidth); + var coordY = (Top - origScreen.WorkingArea.Top) / (origScreen.WorkingArea.Height - ActualHeight); + Left = (screen.WorkingArea.Width - ActualWidth) * coordX + screen.WorkingArea.Left; + Top = (screen.WorkingArea.Height - ActualHeight) * coordY + screen.WorkingArea.Top; + } - Show(); - Activate(); - Focus(); - tbQuery.Focus(); - if (selectAll) tbQuery.SelectAll(); - } + Show(); + Activate(); + Focus(); + tbQuery.Focus(); + if (selectAll) tbQuery.SelectAll(); + } - public void ParseArgs(string[] args) { - if (args != null && args.Length > 0) { - switch (args[0].ToLower()) { - case "reloadplugin": - Plugins.Init(); - break; + public void ParseArgs(string[] args) + { + if (args != null && args.Length > 0) + { + switch (args[0].ToLower()) + { + case "reloadplugin": + Plugins.Init(); + break; - case "query": - if (args.Length > 1) { - string query = args[1]; - tbQuery.Text = query; - tbQuery.SelectAll(); - } - break; + case "query": + if (args.Length > 1) + { + string query = args[1]; + tbQuery.Text = query; + tbQuery.SelectAll(); + } + break; - case "hidestart": - HideApp(); - break; + case "hidestart": + HideApp(); + break; - case "installplugin": - var path = args[1]; - if (!File.Exists(path)) { - MessageBox.Show("Plugin " + path + " didn't exist"); - return; - } - PluginInstaller.Install(path); - break; - } - } - } + case "installplugin": + var path = args[1]; + if (!File.Exists(path)) + { + MessageBox.Show("Plugin " + path + " didn't exist"); + return; + } + PluginInstaller.Install(path); + break; + } + } + } - private void MainWindow_OnDeactivated(object sender, EventArgs e) { - if (UserSettingStorage.Instance.HideWhenDeactive) { - HideWox(); - } - } + private void MainWindow_OnDeactivated(object sender, EventArgs e) + { + if (UserSettingStorage.Instance.HideWhenDeactive) + { + HideWox(); + } + } - private bool KListener_hookedKeyboardCallback(KeyEvent keyevent, int vkcode, SpecialKeyState state) { - if (UserSettingStorage.Instance.ReplaceWinR) { - //todo:need refactoring. move those codes to CMD file or expose events - if (keyevent == KeyEvent.WM_KEYDOWN && vkcode == (int)Keys.R && state.WinPressed) { - WinRStroked = true; - Dispatcher.BeginInvoke(new Action(OnWinRPressed)); - return false; - } - if (keyevent == KeyEvent.WM_KEYUP && WinRStroked && vkcode == (int)Keys.LWin) { - WinRStroked = false; - keyboardSimulator.ModifiedKeyStroke(VirtualKeyCode.LWIN, VirtualKeyCode.CONTROL); - return false; - } - } - return true; - } + private bool KListener_hookedKeyboardCallback(KeyEvent keyevent, int vkcode, SpecialKeyState state) + { + if (UserSettingStorage.Instance.ReplaceWinR) + { + //todo:need refactoring. move those codes to CMD file or expose events + if (keyevent == KeyEvent.WM_KEYDOWN && vkcode == (int)Keys.R && state.WinPressed) + { + WinRStroked = true; + Dispatcher.BeginInvoke(new Action(OnWinRPressed)); + return false; + } + if (keyevent == KeyEvent.WM_KEYUP && WinRStroked && vkcode == (int)Keys.LWin) + { + WinRStroked = false; + keyboardSimulator.ModifiedKeyStroke(VirtualKeyCode.LWIN, VirtualKeyCode.CONTROL); + return false; + } + } + return true; + } - private void OnWinRPressed() { - ShowWox(false); - if (!tbQuery.Text.StartsWith(">")) { - resultCtrl.Clear(); - ChangeQuery(">"); - } - tbQuery.CaretIndex = tbQuery.Text.Length; - tbQuery.SelectionStart = 1; - tbQuery.SelectionLength = tbQuery.Text.Length - 1; - } + private void OnWinRPressed() + { + ShowWox(false); + if (!tbQuery.Text.StartsWith(">")) + { + resultCtrl.Clear(); + ChangeQuery(">"); + } + tbQuery.CaretIndex = tbQuery.Text.Length; + tbQuery.SelectionStart = 1; + tbQuery.SelectionLength = tbQuery.Text.Length - 1; + } - private void updateCmdMode() { - var selected = resultCtrl.AcceptSelect(); - if (selected != null) { - ignoreTextChange = true; - tbQuery.Text = ">" + selected.Title; - tbQuery.CaretIndex = tbQuery.Text.Length; - } - } + private void updateCmdMode() + { + var selected = resultCtrl.AcceptSelect(); + if (selected != null) + { + ignoreTextChange = true; + tbQuery.Text = ">" + selected.Title; + tbQuery.CaretIndex = tbQuery.Text.Length; + } + } - private void TbQuery_OnPreviewKeyDown(object sender, KeyEventArgs e) { - //when alt is pressed, the real key should be e.SystemKey + private void TbQuery_OnPreviewKeyDown(object sender, KeyEventArgs e) + { + //when alt is pressed, the real key should be e.SystemKey - Action Shift_GoBack = () => { - if (e.KeyboardDevice.IsKeyDown(Key.LeftShift) || e.KeyboardDevice.IsKeyDown(Key.RightShift)) { - if (tbQuery.Text.EndsWith("\\")) { - tbQuery.Text = tbQuery.Text.Remove(tbQuery.Text.Length - 1); - } + Action Shift_GoBack = () => + { + if (e.KeyboardDevice.IsKeyDown(Key.LeftShift) || e.KeyboardDevice.IsKeyDown(Key.RightShift)) + { + if (tbQuery.Text.EndsWith("\\")) + { + tbQuery.Text = tbQuery.Text.Remove(tbQuery.Text.Length - 1); + } - if (tbQuery.Text.Contains("\\")) { - var index = tbQuery.Text.LastIndexOf("\\"); - tbQuery.Text = tbQuery.Text.Remove(index) + "\\"; - } - else { - tbQuery.Text = ""; - return; - } - } + if (tbQuery.Text.Contains("\\")) + { + var index = tbQuery.Text.LastIndexOf("\\"); + tbQuery.Text = tbQuery.Text.Remove(index) + "\\"; + } + else + { + tbQuery.Text = ""; + return; + } + } - tbQuery.CaretIndex = int.MaxValue; - }; + tbQuery.CaretIndex = int.MaxValue; + }; - Key key = (e.Key == Key.System ? e.SystemKey : e.Key); - switch (key) { - case Key.Escape: - HideWox(); - e.Handled = true; - break; + Key key = (e.Key == Key.System ? e.SystemKey : e.Key); + switch (key) + { + case Key.Escape: + HideWox(); + e.Handled = true; + break; - case Key.Down: - resultCtrl.SelectNext(); - if (isCMDMode) updateCmdMode(); - toolTip.IsOpen = false; - e.Handled = true; - break; + case Key.Down: + resultCtrl.SelectNext(); + if (isCMDMode) updateCmdMode(); + toolTip.IsOpen = false; + e.Handled = true; + break; - case Key.Up: - resultCtrl.SelectPrev(); - if (isCMDMode) updateCmdMode(); - toolTip.IsOpen = false; - e.Handled = true; - break; + case Key.Up: + resultCtrl.SelectPrev(); + if (isCMDMode) updateCmdMode(); + toolTip.IsOpen = false; + e.Handled = true; + break; - case Key.PageDown: - resultCtrl.SelectNextPage(); - if (isCMDMode) updateCmdMode(); - toolTip.IsOpen = false; - e.Handled = true; - break; + case Key.PageDown: + resultCtrl.SelectNextPage(); + if (isCMDMode) updateCmdMode(); + toolTip.IsOpen = false; + e.Handled = true; + break; - case Key.PageUp: - resultCtrl.SelectPrevPage(); - if (isCMDMode) updateCmdMode(); - toolTip.IsOpen = false; - e.Handled = true; - break; + case Key.PageUp: + resultCtrl.SelectPrevPage(); + if (isCMDMode) updateCmdMode(); + toolTip.IsOpen = false; + e.Handled = true; + break; - case Key.Enter: - Shift_GoBack(); - AcceptSelect(resultCtrl.AcceptSelect()); - e.Handled = true; - break; + case Key.Enter: + Shift_GoBack(); + AcceptSelect(resultCtrl.AcceptSelect()); + e.Handled = true; + break; - case Key.Tab: - Shift_GoBack(); - AcceptSelect(resultCtrl.AcceptSelect()); - if (!tbQuery.Text.EndsWith("\\")) tbQuery.Text += "\\"; - AcceptSelect(resultCtrl.AcceptSelect()); - tbQuery.CaretIndex = int.MaxValue; - e.Handled = true; - break; - } - } + case Key.Tab: + Shift_GoBack(); + AcceptSelect(resultCtrl.AcceptSelect()); + if (!tbQuery.Text.EndsWith("\\")) tbQuery.Text += "\\"; + AcceptSelect(resultCtrl.AcceptSelect()); + tbQuery.CaretIndex = int.MaxValue; + e.Handled = true; + break; + } + } - private void AcceptSelect(Result result) { - if (!resultCtrl.Dirty && result != null) { - if (result.Action != null) { - bool hideWindow = result.Action(new ActionContext() { - SpecialKeyState = new GlobalHotkey().CheckModifiers() - }); - if (hideWindow) { - HideWox(); - } - UserSelectedRecordStorage.Instance.Add(result); - } - } - } + private void AcceptSelect(Result result) + { + if (!resultCtrl.Dirty && result != null) + { + if (result.Action != null) + { + bool hideWindow = result.Action(new ActionContext() + { + SpecialKeyState = new GlobalHotkey().CheckModifiers() + }); + if (hideWindow) + { + HideWox(); + } + UserSelectedRecordStorage.Instance.Add(result); + } + } + } - public void OnUpdateResultView(List list) { + public void OnUpdateResultView(List list) + { queryHasReturn = true; progressBar.Dispatcher.Invoke(new Action(StopProgress)); - if (list == null || list.Count == 0) return; + if (list == null || list.Count == 0) return; if (list.Count > 0) { @@ -478,58 +587,65 @@ namespace Wox { resultCtrl.AddResults(l); })), TimeSpan.FromMilliseconds(isCMDMode ? 0 : 50)); } - } + } - public void SetTheme(string themeName) { - var dict = new ResourceDictionary { - Source = new Uri(Path.Combine(Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), "Themes\\" + themeName + ".xaml"), UriKind.Absolute) - }; + public void SetTheme(string themeName) + { + var dict = new ResourceDictionary + { + Source = new Uri(Path.Combine(Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), "Themes\\" + themeName + ".xaml"), UriKind.Absolute) + }; - Style queryBoxStyle = dict["QueryBoxStyle"] as Style; - if (queryBoxStyle != null) { - queryBoxStyle.Setters.Add(new Setter(TextBox.FontFamilyProperty, new FontFamily(UserSettingStorage.Instance.QueryBoxFont))); - queryBoxStyle.Setters.Add(new Setter(TextBox.FontStyleProperty, FontHelper.GetFontStyleFromInvariantStringOrNormal(UserSettingStorage.Instance.QueryBoxFontStyle))); - queryBoxStyle.Setters.Add(new Setter(TextBox.FontWeightProperty, FontHelper.GetFontWeightFromInvariantStringOrNormal(UserSettingStorage.Instance.QueryBoxFontWeight))); - queryBoxStyle.Setters.Add(new Setter(TextBox.FontStretchProperty, FontHelper.GetFontStretchFromInvariantStringOrNormal(UserSettingStorage.Instance.QueryBoxFontStretch))); - } + Style queryBoxStyle = dict["QueryBoxStyle"] as Style; + if (queryBoxStyle != null) + { + queryBoxStyle.Setters.Add(new Setter(TextBox.FontFamilyProperty, new FontFamily(UserSettingStorage.Instance.QueryBoxFont))); + queryBoxStyle.Setters.Add(new Setter(TextBox.FontStyleProperty, FontHelper.GetFontStyleFromInvariantStringOrNormal(UserSettingStorage.Instance.QueryBoxFontStyle))); + queryBoxStyle.Setters.Add(new Setter(TextBox.FontWeightProperty, FontHelper.GetFontWeightFromInvariantStringOrNormal(UserSettingStorage.Instance.QueryBoxFontWeight))); + queryBoxStyle.Setters.Add(new Setter(TextBox.FontStretchProperty, FontHelper.GetFontStretchFromInvariantStringOrNormal(UserSettingStorage.Instance.QueryBoxFontStretch))); + } - Style resultItemStyle = dict["ItemTitleStyle"] as Style; - Style resultSubItemStyle = dict["ItemSubTitleStyle"] as Style; - Style resultItemSelectedStyle = dict["ItemTitleSelectedStyle"] as Style; - Style resultSubItemSelectedStyle = dict["ItemSubTitleSelectedStyle"] as Style; - if (resultItemStyle != null && resultSubItemStyle != null && resultSubItemSelectedStyle != null && resultItemSelectedStyle != null) { - Setter fontFamily = new Setter(TextBlock.FontFamilyProperty, new FontFamily(UserSettingStorage.Instance.ResultItemFont)); - Setter fontStyle = new Setter(TextBlock.FontStyleProperty, FontHelper.GetFontStyleFromInvariantStringOrNormal(UserSettingStorage.Instance.ResultItemFontStyle)); - Setter fontWeight = new Setter(TextBlock.FontWeightProperty, FontHelper.GetFontWeightFromInvariantStringOrNormal(UserSettingStorage.Instance.ResultItemFontWeight)); - Setter fontStretch = new Setter(TextBlock.FontStretchProperty, FontHelper.GetFontStretchFromInvariantStringOrNormal(UserSettingStorage.Instance.ResultItemFontStretch)); + Style resultItemStyle = dict["ItemTitleStyle"] as Style; + Style resultSubItemStyle = dict["ItemSubTitleStyle"] as Style; + Style resultItemSelectedStyle = dict["ItemTitleSelectedStyle"] as Style; + Style resultSubItemSelectedStyle = dict["ItemSubTitleSelectedStyle"] as Style; + if (resultItemStyle != null && resultSubItemStyle != null && resultSubItemSelectedStyle != null && resultItemSelectedStyle != null) + { + Setter fontFamily = new Setter(TextBlock.FontFamilyProperty, new FontFamily(UserSettingStorage.Instance.ResultItemFont)); + Setter fontStyle = new Setter(TextBlock.FontStyleProperty, FontHelper.GetFontStyleFromInvariantStringOrNormal(UserSettingStorage.Instance.ResultItemFontStyle)); + Setter fontWeight = new Setter(TextBlock.FontWeightProperty, FontHelper.GetFontWeightFromInvariantStringOrNormal(UserSettingStorage.Instance.ResultItemFontWeight)); + Setter fontStretch = new Setter(TextBlock.FontStretchProperty, FontHelper.GetFontStretchFromInvariantStringOrNormal(UserSettingStorage.Instance.ResultItemFontStretch)); - Setter[] setters = new Setter[] { fontFamily, fontStyle, fontWeight, fontStretch }; - Array.ForEach(new Style[] { resultItemStyle, resultSubItemStyle, resultItemSelectedStyle, resultSubItemSelectedStyle }, o => Array.ForEach(setters, p => o.Setters.Add(p))); - } + Setter[] setters = new Setter[] { fontFamily, fontStyle, fontWeight, fontStretch }; + Array.ForEach(new Style[] { resultItemStyle, resultSubItemStyle, resultItemSelectedStyle, resultSubItemSelectedStyle }, o => Array.ForEach(setters, p => o.Setters.Add(p))); + } - Application.Current.Resources.MergedDictionaries.Clear(); - Application.Current.Resources.MergedDictionaries.Add(dict); + Application.Current.Resources.MergedDictionaries.Clear(); + Application.Current.Resources.MergedDictionaries.Add(dict); - this.Opacity = this.AllowsTransparency ? UserSettingStorage.Instance.Opacity : 1; - } + this.Opacity = this.AllowsTransparency ? UserSettingStorage.Instance.Opacity : 1; + } - public bool ShellRun(string cmd) { - try { - if (string.IsNullOrEmpty(cmd)) - throw new ArgumentNullException(); + public bool ShellRun(string cmd) + { + try + { + if (string.IsNullOrEmpty(cmd)) + throw new ArgumentNullException(); - Wox.Infrastructure.WindowsShellRun.Start(cmd); - return true; - } - catch (Exception ex) { - ShowMsg("Could not start " + cmd, ex.Message, null); - } - return false; - } + Wox.Infrastructure.WindowsShellRun.Start(cmd); + return true; + } + catch (Exception ex) + { + ShowMsg("Could not start " + cmd, ex.Message, null); + } + return false; + } - private void MainWindow_OnDrop(object sender, DragEventArgs e) - { + private void MainWindow_OnDrop(object sender, DragEventArgs e) + { if (e.Data.GetDataPresent(System.Windows.DataFormats.FileDrop)) { // Note that you can have more than one file. @@ -543,11 +659,11 @@ namespace Wox { MessageBox.Show("incorrect wox plugin file."); } } - } + } - private void TbQuery_OnPreviewDragOver(object sender, DragEventArgs e) - { - e.Handled = true; - } - } + private void TbQuery_OnPreviewDragOver(object sender, DragEventArgs e) + { + e.Handled = true; + } + } } \ No newline at end of file diff --git a/Wox/PluginLoader/ExecutablePluginLoader.cs b/Wox/PluginLoader/ExecutablePluginLoader.cs new file mode 100644 index 0000000000..e49e08ae9b --- /dev/null +++ b/Wox/PluginLoader/ExecutablePluginLoader.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Wox.Plugin; + +namespace Wox.PluginLoader +{ + public class ExecutablePluginLoader : BasePluginLoader + { + public override List LoadPlugin() + { + List plugins = new List(); + List metadatas = pluginMetadatas.Where(o => o.Language.ToUpper() == AllowedLanguage.ExecutableFile.ToUpper()).ToList(); + foreach (PluginMetadata metadata in metadatas) + { + ExecutablePluginWrapper executer = new ExecutablePluginWrapper(); + PluginPair pair = new PluginPair() + { + Plugin = executer, + Metadata = metadata + }; + plugins.Add(pair); + } + + return plugins; + } + } +} diff --git a/Wox/PluginLoader/ExecutablePluginWrapper.cs b/Wox/PluginLoader/ExecutablePluginWrapper.cs new file mode 100644 index 0000000000..a638c7a51a --- /dev/null +++ b/Wox/PluginLoader/ExecutablePluginWrapper.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using Newtonsoft.Json; +using Wox.Plugin; +using Wox.RPC; + +namespace Wox.PluginLoader +{ + public class ExecutablePluginWrapper : IPlugin + { + private PluginInitContext context; + private static string executeDirectory = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath); + + public List Query(Query query) + { + List results = new List(); + try + { + ProcessStartInfo start = new ProcessStartInfo(); + start.FileName = Path.Combine(executeDirectory, "PYTHONTHOME\\Scripts\\python.exe"); + start.Arguments = string.Format("{0} \"{1}\"", + context.CurrentPluginMetadata.ExecuteFilePath, + RPC.JsonRPC.GetRPC("query", query.GetAllRemainingParameter())); + start.UseShellExecute = false; + start.CreateNoWindow = true; + start.RedirectStandardOutput = true; + using (Process process = Process.Start(start)) + { + if (process != null) + { + using (StreamReader reader = process.StandardOutput) + { + string output = reader.ReadToEnd(); + if (!string.IsNullOrEmpty(output)) + { + JsonPRCModel rpc = JsonConvert.DeserializeObject(output); + var rpcresults = JsonConvert.DeserializeObject>(rpc.result); + List r = new List(); + foreach (ActionJsonRPCResult result in rpcresults) + { + if (!string.IsNullOrEmpty(result.ActionJSONRPC)) + { + result.Action = (context) => + { + return true; + }; + } + r.Add(result); + } + return r; + } + } + } + } + } + catch + { + } + + return results; + } + + public void Init(PluginInitContext context) + { + this.context = context; + } + } +} diff --git a/Wox/PluginLoader/Plugins.cs b/Wox/PluginLoader/Plugins.cs index d12a0240ba..03eecab4fc 100644 --- a/Wox/PluginLoader/Plugins.cs +++ b/Wox/PluginLoader/Plugins.cs @@ -1,96 +1,64 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading; -using Microsoft.CSharp; using Wox.Helper; -using Wox.Infrastructure; -using Wox.Infrastructure.Storage; -using Wox.Infrastructure.Storage.UserSettings; using Wox.Plugin; -namespace Wox.PluginLoader { - public static class Plugins { - //private static string debuggerMode = null; - public static String DebuggerMode { get; private set; } +namespace Wox.PluginLoader +{ + public static class Plugins + { + public static String DebuggerMode { get; private set; } + private static List plugins = new List(); - private static List plugins = new List(); - private static ManualResetEvent initializing = null; + public static void Init() + { + plugins.Clear(); + BasePluginLoader.ParsePluginsConfig(); - public static void Init() { - if (initializing != null) return; + plugins.AddRange(new PythonPluginLoader().LoadPlugin()); + plugins.AddRange(new CSharpPluginLoader().LoadPlugin()); + plugins.AddRange(new ExecutablePluginLoader().LoadPlugin()); - initializing = new ManualResetEvent(false); - plugins.Clear(); - BasePluginLoader.ParsePluginsConfig(); - - plugins.AddRange(new PythonPluginLoader().LoadPlugin()); - plugins.AddRange(new CSharpPluginLoader().LoadPlugin()); - Forker forker = new Forker(); - foreach (IPlugin plugin in plugins.Select(pluginPair => pluginPair.Plugin)) { - IPlugin plugin1 = plugin; - PluginPair pluginPair = plugins.FirstOrDefault(o => o.Plugin == plugin1); - if (pluginPair != null) { - PluginMetadata metadata = pluginPair.Metadata; - pluginPair.InitContext = new PluginInitContext() { - Plugins = plugins, - CurrentPluginMetadata = metadata, - ChangeQuery = s => App.Window.Dispatcher.Invoke(new Action(() => App.Window.ChangeQuery(s))), - CloseApp = () => App.Window.Dispatcher.Invoke(new Action(() => App.Window.CloseApp())), - HideApp = () => App.Window.Dispatcher.Invoke(new Action(() => App.Window.HideApp())), - ShowApp = () => App.Window.Dispatcher.Invoke(new Action(() => App.Window.ShowApp())), - ShowMsg = (title, subTitle, iconPath) => App.Window.Dispatcher.Invoke(new Action(() => - App.Window.ShowMsg(title, subTitle, iconPath))), - OpenSettingDialog = () => App.Window.Dispatcher.Invoke(new Action(() => App.Window.OpenSettingDialog())), - ShowCurrentResultItemTooltip = (msg) => App.Window.Dispatcher.Invoke(new Action(() => App.Window.ShowCurrentResultItemTooltip(msg))), - ReloadPlugins = () => App.Window.Dispatcher.Invoke(new Action(() => Init())), - InstallPlugin = (filePath) => App.Window.Dispatcher.Invoke(new Action(() => { - PluginInstaller.Install(filePath); - })), - StartLoadingBar = () => App.Window.Dispatcher.Invoke(new Action(() => App.Window.StartLoadingBar())), - StopLoadingBar = () => App.Window.Dispatcher.Invoke(new Action(() => App.Window.StopLoadingBar())), - //ShellRun = (cmd) => (bool)App.Window.Dispatcher.Invoke(new Func(() => App.Window.ShellRun(cmd))) - }; + Forker forker = new Forker(); + foreach (IPlugin plugin in plugins.Select(pluginPair => pluginPair.Plugin)) + { + IPlugin plugin1 = plugin; + PluginPair pluginPair = plugins.FirstOrDefault(o => o.Plugin == plugin1); + if (pluginPair != null) + { + PluginMetadata metadata = pluginPair.Metadata; + pluginPair.InitContext = new PluginInitContext() + { + CurrentPluginMetadata = metadata, + API = App.Window + }; - pluginPair.InitContext.ShellRun = (cmd) => { - try { - return (bool)App.Window.Dispatcher.Invoke(new Func(() => App.Window.ShellRun(cmd))); - } - catch (Exception) { - return false; - } - }; + forker.Fork(() => plugin1.Init(pluginPair.InitContext)); + } + } - forker.Fork(() => plugin1.Init(pluginPair.InitContext)); - } - } + forker.Join(); + } - ThreadPool.QueueUserWorkItem(o => { - forker.Join(); - initializing.Set(); - initializing = null; - }); - } + public static List AllPlugins + { + get + { + return plugins; + } + } - public static List AllPlugins { - get { - var init = initializing; - if (init != null) { - init.WaitOne(); - } - return plugins; - } - } + public static bool HitThirdpartyKeyword(Query query) + { + if (string.IsNullOrEmpty(query.ActionName)) return false; - public static bool HitThirdpartyKeyword(Query query) { - if (string.IsNullOrEmpty(query.ActionName)) return false; + return plugins.Any(o => o.Metadata.PluginType == PluginType.ThirdParty && o.Metadata.ActionKeyword == query.ActionName); + } - return plugins.Any(o => o.Metadata.PluginType == PluginType.ThirdParty && o.Metadata.ActionKeyword == query.ActionName); - } - - public static void ActivatePluginDebugger(string path) { - DebuggerMode = path; - } - } + public static void ActivatePluginDebugger(string path) + { + DebuggerMode = path; + } + } } diff --git a/Wox/RPC/JsonPRCModel.cs b/Wox/RPC/JsonPRCModel.cs new file mode 100644 index 0000000000..79d133b535 --- /dev/null +++ b/Wox/RPC/JsonPRCModel.cs @@ -0,0 +1,17 @@ +using Wox.Plugin; + +namespace Wox.RPC +{ + public class JsonPRCModel + { + public int id { get; set; } + public string jsonrpc { get; set; } + + public string result { get; set; } + } + + public class ActionJsonRPCResult : Result + { + public string ActionJSONRPC { get; set; } + } +} diff --git a/Wox/RPC/JsonRPC.cs b/Wox/RPC/JsonRPC.cs new file mode 100644 index 0000000000..3ce2cb5725 --- /dev/null +++ b/Wox/RPC/JsonRPC.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Wox.RPC +{ + public class JsonRPC + { + public static string GetRPC(string method, List paras) + { + var list = paras.Select(s => string.Format(@"\""{0}\""", s)); + return string.Format(@"{{\""jsonrpc\"": \""2.0\"",\""method\"": \""{0}\"", \""params\"": [{1}], \""id\"": 1}}", + method, string.Join(",", list.ToArray())); + } + + public static string GetRPC(string method, string para) + { + return GetRPC(method, new List() { para }); + } + } +} diff --git a/Wox/Wox.csproj b/Wox/Wox.csproj index 53e586e22b..c67f6f5efc 100644 --- a/Wox/Wox.csproj +++ b/Wox/Wox.csproj @@ -138,11 +138,15 @@ HotkeyControl.xaml + Msg.xaml + + +