abstract plugin interface

This commit is contained in:
Paddy Xu
2018-01-27 16:22:48 +02:00
parent d50d757022
commit 56af2311b9
87 changed files with 2844 additions and 2703 deletions

View File

@@ -0,0 +1,259 @@
// Copyright © 2017 Paddy Xu
//
// This file is part of QuickLook program.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Windows;
using QuickLook.Common.Annotations;
using QuickLook.Common.Helpers;
namespace QuickLook.Common
{
/// <summary>
/// A runtime object which allows interaction between this plugin and QuickLook.
/// </summary>
public class ContextObject : INotifyPropertyChanged
{
private bool _canResize = true;
private bool _fullWindowDragging;
private bool _isBusy = true;
private string _title = string.Empty;
private bool _titlebarAutoHide;
private bool _titlebarBlurVisibility;
private bool _titlebarColourVisibility = true;
private bool _titlebarOverlap;
private bool _useDarkTheme;
private object _viewerContent;
/// <summary>
/// Get or set the title of Viewer window.
/// </summary>
public string Title
{
get => _title;
set
{
_title = value;
OnPropertyChanged();
}
}
/// <summary>
/// Get or set the viewer content control.
/// </summary>
public object ViewerContent
{
get => _viewerContent;
set
{
_viewerContent = value;
OnPropertyChanged();
}
}
/// <summary>
/// Show or hide the busy indicator icon.
/// </summary>
public bool IsBusy
{
get => _isBusy;
set
{
_isBusy = value;
OnPropertyChanged();
}
}
/// <summary>
/// Set the exact size you want.
/// </summary>
public Size PreferredSize { get; set; } = new Size {Width = 800, Height = 600};
/// <summary>
/// Set whether user are allowed to resize the viewer window.
/// </summary>
public bool CanResize
{
get => _canResize;
set
{
_canResize = value;
OnPropertyChanged();
}
}
/// <summary>
/// Set whether the full viewer window can be used for mouse dragging.
/// </summary>
public bool FullWindowDragging
{
get => _fullWindowDragging;
set
{
_fullWindowDragging = value;
OnPropertyChanged();
}
}
/// <summary>
/// Set whether the viewer content is overlapped by the title bar
/// </summary>
public bool TitlebarOverlap
{
get => _titlebarOverlap;
set
{
_titlebarOverlap = value;
OnPropertyChanged();
}
}
/// <summary>
/// Set whether the title bar shows a blurred background
/// </summary>
public bool TitlebarBlurVisibility
{
get => _titlebarBlurVisibility;
set
{
if (value == _titlebarBlurVisibility) return;
_titlebarBlurVisibility = value;
OnPropertyChanged();
}
}
/// <summary>
/// Set whether the title bar shows a colour overlay
/// </summary>
public bool TitlebarColourVisibility
{
get => _titlebarColourVisibility;
set
{
if (value == _titlebarColourVisibility) return;
_titlebarColourVisibility = value;
OnPropertyChanged();
}
}
/// <summary>
/// Should the titlebar hides itself after a short period of inactivity?
/// </summary>
public bool TitlebarAutoHide
{
get => _titlebarAutoHide;
set
{
if (value == _titlebarAutoHide) return;
_titlebarAutoHide = value;
OnPropertyChanged();
}
}
/// <summary>
/// Switch to dark theme?
/// </summary>
public bool UseDarkTheme
{
get => _useDarkTheme;
set
{
_useDarkTheme = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Get a string from translation Xml document.
/// </summary>
[MethodImpl(MethodImplOptions.NoInlining)]
public string GetString(string id, string file = null, CultureInfo locale = null, string failsafe = null)
{
return TranslationHelper.Get(id, file, locale, failsafe, Assembly.GetCallingAssembly());
}
/// <summary>
/// Get a setting from Xml document.
/// </summary>
[MethodImpl(MethodImplOptions.NoInlining)]
public T GetSetting<T>(string id, T failsafe = default(T))
{
return SettingHelper.Get(id, failsafe, Assembly.GetCallingAssembly());
}
/// <summary>
/// Set a setting from Xml document.
/// </summary>
[MethodImpl(MethodImplOptions.NoInlining)]
public void SetSetting(string id, object value)
{
SettingHelper.Set(id, value, Assembly.GetCallingAssembly());
}
/// <summary>
/// Set the size of viewer window, scale or shrink to fit (to screen resolution).
/// The window can take maximum (maxRatio*resolution) space.
/// </summary>
/// <param name="size">The desired size.</param>
/// <param name="maxRatio">The maximum percent (over screen resolution) it can take.</param>
public double SetPreferredSizeFit(Size size, double maxRatio)
{
if (maxRatio > 1)
maxRatio = 1;
var max = WindowHelper.GetCurrentWindowRect();
var widthRatio = max.Width * maxRatio / size.Width;
var heightRatio = max.Height * maxRatio / size.Height;
var ratio = Math.Min(widthRatio, heightRatio);
if (ratio > 1) ratio = 1;
PreferredSize = new Size {Width = size.Width * ratio, Height = size.Height * ratio};
return ratio;
}
public void Reset()
{
Title = string.Empty;
IsBusy = true;
PreferredSize = new Size();
CanResize = true;
FullWindowDragging = false;
UseDarkTheme = false;
TitlebarOverlap = false;
TitlebarAutoHide = false;
TitlebarBlurVisibility = false;
TitlebarColourVisibility = true;
ViewerContent = null;
}
[NotifyPropertyChangedInvocator]
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

View File

@@ -0,0 +1,152 @@
// Copyright © 2017 Paddy Xu
//
// This file is part of QuickLook program.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using PixelFormat = System.Windows.Media.PixelFormat;
namespace QuickLook.Common.ExtensionMethods
{
public static class BitmapExtensions
{
public static BitmapSource ToBitmapSource(this Bitmap source)
{
var orgSource = source;
BitmapSource bs = null;
try
{
var data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height),
ImageLockMode.ReadOnly, source.PixelFormat);
// BitmapSource.Create throws an exception when the image is scanned backward.
// The Clone() will make it back scanning forward.
if (data.Stride < 0)
{
source.UnlockBits(data);
source = (Bitmap) source.Clone();
data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height),
ImageLockMode.ReadOnly, source.PixelFormat);
}
bs = BitmapSource.Create(source.Width, source.Height, Math.Floor(source.HorizontalResolution),
Math.Floor(source.VerticalResolution), ConvertPixelFormat(source.PixelFormat), null,
data.Scan0, data.Stride * source.Height, data.Stride);
source.UnlockBits(data);
bs.Freeze();
}
catch
{
// ignored
}
finally
{
if (orgSource != source)
source.Dispose();
}
return bs;
}
public static Bitmap ToBitmap(this BitmapSource source)
{
using (var outStream = new MemoryStream())
{
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(source));
enc.Save(outStream);
var bitmap = new Bitmap(outStream);
return new Bitmap(bitmap);
}
}
private static PixelFormat ConvertPixelFormat(
System.Drawing.Imaging.PixelFormat sourceFormat)
{
switch (sourceFormat)
{
case System.Drawing.Imaging.PixelFormat.Format24bppRgb:
return PixelFormats.Bgr24;
case System.Drawing.Imaging.PixelFormat.Format32bppArgb:
return PixelFormats.Bgra32;
case System.Drawing.Imaging.PixelFormat.Format32bppRgb:
return PixelFormats.Bgr32;
}
return new PixelFormat();
}
public static bool IsDarkImage(this Bitmap image)
{
// convert to 24-bit RGB image
image = image.Clone(new Rectangle(0, 0, image.Width, image.Height),
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
var sampleCount = (int) (0.2 * 400 * 400);
const int pixelSize = 24 / 8;
var data = image.LockBits(new Rectangle(0, 0, image.Width, image.Height),
ImageLockMode.ReadWrite, image.PixelFormat);
var darks = 0;
unsafe
{
var pFirst = (byte*) data.Scan0;
Parallel.For(0, sampleCount, n =>
{
var rand = new Random(n);
var row = rand.Next(0, data.Height);
var col = rand.Next(0, data.Width);
var pos = pFirst + row * data.Stride + col * pixelSize;
var b = pos[0];
var g = pos[1];
var r = pos[2];
var y = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
if (y < 0.5)
darks++;
});
}
image.UnlockBits(data);
image.Dispose();
return darks > 0.65 * sampleCount;
}
public static BitmapImage LoadBitmapImage(this Uri source)
{
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.UriSource = source;
bitmap.EndInit();
return bitmap;
}
}
}

View File

@@ -0,0 +1,47 @@
// Copyright © 2017 Paddy Xu
//
// This file is part of QuickLook program.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Threading.Tasks;
using System.Windows.Threading;
namespace QuickLook.Common.ExtensionMethods
{
public static class DispatcherExtensions
{
public static void Delay(this Dispatcher disp, int delayMs,
Action<object> action, object parm = null)
{
Task.Delay(delayMs).ContinueWith(t => { disp.Invoke(action, parm); });
}
public static void DelayWithPriority(this Dispatcher disp, int delayMs,
Action<object> action, object parm = null,
DispatcherPriority priority = DispatcherPriority.ApplicationIdle)
{
Task.Delay(delayMs).ContinueWith(t => { disp.BeginInvoke(action, priority, parm); });
}
public static async Task DelayAsync(this Dispatcher disp, int delayMs,
Action<object> action, object parm = null,
DispatcherPriority priority = DispatcherPriority.ApplicationIdle)
{
await Task.Delay(delayMs);
await disp.BeginInvoke(action, priority, parm);
}
}
}

View File

@@ -0,0 +1,31 @@
// Copyright © 2017 Paddy Xu
//
// This file is part of QuickLook program.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
namespace QuickLook.Common.ExtensionMethods
{
public static class EnumerableExtensions
{
public static void ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
{
foreach (var item in enumeration)
action(item);
}
}
}

View File

@@ -0,0 +1,48 @@
// Copyright © 2017 Paddy Xu
//
// This file is part of QuickLook program.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace QuickLook.Common.ExtensionMethods
{
public static class FileExtensions
{
public static string ToPrettySize(this long value, int decimalPlaces = 0)
{
const long OneKb = 1024;
const long OneMb = OneKb * 1024;
const long OneGb = OneMb * 1024;
const long OneTb = OneGb * 1024;
var asTb = Math.Round((double) value / OneTb, decimalPlaces);
var asGb = Math.Round((double) value / OneGb, decimalPlaces);
var asMb = Math.Round((double) value / OneMb, decimalPlaces);
var asKb = Math.Round((double) value / OneKb, decimalPlaces);
var chosenValue = asTb > 1
? $"{asTb} TB"
: asGb > 1
? $"{asGb} GB"
: asMb > 1
? $"{asMb} MB"
: asKb > 1
? $"{asKb} KB"
: $"{Math.Round((double) value, decimalPlaces)} bytes";
return chosenValue;
}
}
}

View File

@@ -0,0 +1,29 @@
// Copyright © 2017 Paddy Xu
//
// This file is part of QuickLook program.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace QuickLook.Common.ExtensionMethods
{
public static class TypeExtensions
{
public static T CreateInstance<T>(this Type t)
{
return (T) Activator.CreateInstance(t);
}
}
}

View File

@@ -0,0 +1,60 @@
// Copyright © 2017 Paddy Xu
//
// This file is part of QuickLook program.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Drawing;
using System.Runtime.InteropServices;
namespace QuickLook.Common.Helpers
{
public static class DpiHelper
{
public const float DefaultDpi = 96;
public static ScaleFactor GetCurrentScaleFactor()
{
var g = Graphics.FromHwnd(IntPtr.Zero);
var desktop = g.GetHdc();
var horizontalDpi = GetDeviceCaps(desktop, (int) DeviceCap.LOGPIXELSX);
var verticalDpi = GetDeviceCaps(desktop, (int) DeviceCap.LOGPIXELSY);
return new ScaleFactor {Horizontal = horizontalDpi / DefaultDpi, Vertical = verticalDpi / DefaultDpi};
}
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
private static extern int GetDeviceCaps(IntPtr hDC, int nIndex);
private enum DeviceCap
{
/// <summary>
/// Logical pixels inch in X
/// </summary>
LOGPIXELSX = 88,
/// <summary>
/// Logical pixels inch in Y
/// </summary>
LOGPIXELSY = 90
}
public struct ScaleFactor
{
public float Horizontal;
public float Vertical;
}
}
}

View File

@@ -0,0 +1,134 @@
// Copyright © 2017 Paddy Xu
//
// This file is part of QuickLook program.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace QuickLook.Common.Helpers
{
public class FileHelper
{
public static bool IsExecutable(string path, out string appFriendlyName)
{
appFriendlyName = string.Empty;
var ext = Path.GetExtension(path).ToLower();
var isExe = new[] {".cmd", ".bat", ".pif", ".scf", ".exe", ".com", ".scr"}.Contains(ext.ToLower());
if (!isExe)
return false;
appFriendlyName = FileVersionInfo.GetVersionInfo(path).FileDescription;
if (string.IsNullOrEmpty(appFriendlyName))
appFriendlyName = Path.GetFileName(path);
return true;
}
public static bool GetAssocApplication(string path, out string appFriendlyName)
{
appFriendlyName = string.Empty;
var ext = Path.GetExtension(path).ToLower();
// no assoc. app. found
if (string.IsNullOrEmpty(GetAssocApplicationNative(ext, AssocStr.Command)))
if (string.IsNullOrEmpty(GetAssocApplicationNative(ext, AssocStr.AppId))) // UWP
return false;
appFriendlyName = GetAssocApplicationNative(ext, AssocStr.FriendlyAppName);
if (string.IsNullOrEmpty(appFriendlyName))
appFriendlyName = Path.GetFileName(path);
return true;
}
[DllImport("shlwapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern uint AssocQueryString(AssocF flags, AssocStr str, string pszAssoc, string pszExtra,
[Out] StringBuilder sOut, [In] [Out] ref uint nOut);
private static string GetAssocApplicationNative(string fileExtensionIncludingDot, AssocStr str)
{
uint cOut = 0;
if (AssocQueryString(AssocF.Verify | AssocF.RemapRunDll | AssocF.InitIgnoreUnknown, str,
fileExtensionIncludingDot, null, null,
ref cOut) != 1)
return null;
var pOut = new StringBuilder((int) cOut);
if (AssocQueryString(AssocF.Verify | AssocF.RemapRunDll | AssocF.InitIgnoreUnknown, str,
fileExtensionIncludingDot, null, pOut,
ref cOut) != 0)
return null;
return pOut.ToString();
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[Flags]
private enum AssocF
{
InitNoRemapCLSID = 0x1,
InitByExeName = 0x2,
OpenByExeName = 0x2,
InitDefaultToStar = 0x4,
InitDefaultToFolder = 0x8,
NoUserSettings = 0x10,
NoTruncate = 0x20,
Verify = 0x40,
RemapRunDll = 0x80,
NoFixUps = 0x100,
IgnoreBaseClass = 0x200,
InitIgnoreUnknown = 0x400,
InitFixedProgid = 0x800,
IsProtocol = 0x1000,
InitForFile = 0x2000
}
//[SuppressMessage("ReSharper", "InconsistentNaming")]
private enum AssocStr
{
Command = 1,
Executable,
FriendlyDocName,
FriendlyAppName,
NoOpen,
ShellNewValue,
DdeCommand,
DdeIfExec,
DdeApplication,
DdeTopic,
InfoTip,
QuickTip,
TileInfo,
ContentType,
DefaultIcon,
ShellExtension,
DropTarget,
DelegateExecute,
SupportedUriProtocols,
ProgId,
AppId,
AppPublisher,
AppIconReference,
Max
}
}
}

View File

@@ -0,0 +1,79 @@
// Copyright © 2017 Paddy Xu
//
// This file is part of QuickLook program.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Threading.Tasks;
using QuickLook.Common.NativeMethods;
namespace QuickLook.Common.Helpers
{
public class ProcessHelper
{
private const int ErrorInsufficientBuffer = 0x7A;
// ReSharper disable once InconsistentNaming
public static void PerformAggressiveGC()
{
// delay some time to make sure that all windows are closed
Task.Delay(2000).ContinueWith(t => GC.Collect(GC.MaxGeneration));
}
public static bool IsRunningAsUWP()
{
try
{
uint len = 0;
var r = Kernel32.GetCurrentPackageFullName(ref len, null);
return r == ErrorInsufficientBuffer;
}
catch (EntryPointNotFoundException)
{
return false;
}
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public static bool IsOnWindows10S()
{
const uint PRODUCT_CLOUD = 0x000000B2; // Windows 10 S
const uint PRODUCT_CLOUDN = 0x000000B3; // Windows 10 S N
Kernel32.GetProductInfo(Environment.OSVersion.Version.Major,
Environment.OSVersion.Version.Minor, 0, 0, out var osType);
return osType == PRODUCT_CLOUD || osType == PRODUCT_CLOUDN;
}
public static void WriteLog(string msg)
{
var logFilePath = Path.Combine(SettingHelper.LocalDataPath, @"QuickLook.Exception.log");
using (var writer = new StreamWriter(new FileStream(logFilePath, FileMode.OpenOrCreate,
FileAccess.ReadWrite, FileShare.Read)))
{
writer.BaseStream.Seek(0, SeekOrigin.End);
writer.WriteLine($"========{DateTime.Now}========");
writer.WriteLine(msg);
writer.WriteLine();
}
}
}
}

View File

@@ -0,0 +1,116 @@
// Copyright © 2018 Paddy Xu
//
// This file is part of QuickLook program.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Xml;
namespace QuickLook.Common.Helpers
{
public class SettingHelper
{
public static readonly string LocalDataPath =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"pooi.moe\QuickLook\");
private static readonly Dictionary<string, XmlDocument> FileCache = new Dictionary<string, XmlDocument>();
[MethodImpl(MethodImplOptions.NoInlining)]
public static T Get<T>(string id, T failsafe = default(T), Assembly calling = null)
{
if (!typeof(T).IsSerializable && !typeof(ISerializable).IsAssignableFrom(typeof(T)))
throw new InvalidOperationException("A serializable Type is required");
var file = Path.Combine(LocalDataPath,
(calling ?? Assembly.GetCallingAssembly()).GetName().Name + ".config");
var doc = GetConfigFile(file);
// try to get setting
var s = GetSettingFromXml(doc, id, failsafe);
return s != null ? s : failsafe;
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void Set(string id, object value, Assembly calling = null)
{
if (!value.GetType().IsSerializable)
throw new NotSupportedException("New value if not serializable.");
var file = Path.Combine(LocalDataPath,
(calling ?? Assembly.GetCallingAssembly()).GetName().Name + ".config");
WriteSettingToXml(GetConfigFile(file), id, value);
}
private static T GetSettingFromXml<T>(XmlDocument doc, string id, T failsafe)
{
var v = doc.SelectSingleNode($@"/Settings/{id}");
var result = v == null ? failsafe : (T) Convert.ChangeType(v.InnerText, typeof(T));
return result;
}
private static void WriteSettingToXml(XmlDocument doc, string id, object value)
{
var v = doc.SelectSingleNode($@"/Settings/{id}");
if (v != null)
{
v.InnerText = value.ToString();
}
else
{
var node = doc.CreateNode(XmlNodeType.Element, id, doc.NamespaceURI);
node.InnerText = value.ToString();
doc.SelectSingleNode(@"/Settings").AppendChild(node);
}
doc.Save(new Uri(doc.BaseURI).LocalPath);
}
private static XmlDocument GetConfigFile(string file)
{
if (FileCache.ContainsKey(file))
return FileCache[file];
Directory.CreateDirectory(Path.GetDirectoryName(file));
if (!File.Exists(file))
CreateNewConfig(file);
var doc = new XmlDocument();
doc.Load(file);
FileCache.Add(file, doc);
return doc;
}
private static void CreateNewConfig(string file)
{
using (var writer = XmlWriter.Create(file))
{
writer.WriteStartDocument();
writer.WriteStartElement("Settings");
writer.WriteEndElement();
writer.WriteEndDocument();
}
}
}
}

View File

@@ -0,0 +1,86 @@
// Copyright © 2017 Paddy Xu
//
// This file is part of QuickLook program.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Xml.XPath;
namespace QuickLook.Common.Helpers
{
public class TranslationHelper
{
private static readonly CultureInfo CurrentCultureInfo = CultureInfo.CurrentUICulture;
//private static readonly CultureInfo CurrentCultureInfo = CultureInfo.GetCultureInfo("zh-CN");
private static readonly Dictionary<string, XPathNavigator> FileCache = new Dictionary<string, XPathNavigator>();
[MethodImpl(MethodImplOptions.NoInlining)]
public static string Get(string id, string file = null, CultureInfo locale = null, string failsafe = null,
Assembly calling = null)
{
if (file == null)
file = Path.Combine(Path.GetDirectoryName((calling ?? Assembly.GetCallingAssembly()).Location),
"Translations.config");
if (!File.Exists(file))
return failsafe ?? id;
if (locale == null)
locale = CurrentCultureInfo;
var nav = GetLangFile(file);
// try to get string
var s = GetStringFromXml(nav, id, locale);
if (s != null)
return s;
// try again for parent language
if (locale.Parent.Name != string.Empty)
s = GetStringFromXml(nav, id, locale.Parent);
if (s != null)
return s;
// use fallback language
s = GetStringFromXml(nav, id, CultureInfo.GetCultureInfo("en"));
if (s != null)
return s;
return failsafe ?? id;
}
private static string GetStringFromXml(XPathNavigator nav, string id, CultureInfo locale)
{
var result = nav.SelectSingleNode($@"/Translations/{locale.Name}/{id}");
return result?.Value;
}
private static XPathNavigator GetLangFile(string file)
{
if (FileCache.ContainsKey(file))
return FileCache[file];
var res = new XPathDocument(file).CreateNavigator();
FileCache.Add(file, res);
return res;
}
}
}

View File

@@ -0,0 +1,157 @@
// Copyright © 2017 Paddy Xu
//
// This file is part of QuickLook program.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Interop;
using System.Windows.Media;
using QuickLook.Common.NativeMethods;
namespace QuickLook.Common.Helpers
{
public static class WindowHelper
{
public enum WindowCompositionAttribute
{
WcaAccentPolicy = 19
}
public static Rect GetCurrentWindowRect()
{
var screen = Screen.FromPoint(Cursor.Position).WorkingArea;
var scale = DpiHelper.GetCurrentScaleFactor();
return new Rect(
new Point(screen.X / scale.Horizontal, screen.Y / scale.Vertical),
new Size(screen.Width / scale.Horizontal, screen.Height / scale.Vertical));
}
public static void BringToFront(this Window window)
{
var handle = new WindowInteropHelper(window).Handle;
User32.SetWindowPos(handle, User32.HWND_TOPMOST, 0, 0, 0, 0,
User32.SWP_NOMOVE | User32.SWP_NOSIZE | User32.SWP_NOACTIVATE);
User32.SetWindowPos(handle, User32.HWND_NOTOPMOST, 0, 0, 0, 0,
User32.SWP_NOMOVE | User32.SWP_NOSIZE | User32.SWP_NOACTIVATE);
}
public static void MoveWindow(this Window window,
double left,
double top,
double width,
double height)
{
int pxLeft = 0, pxTop = 0;
if (left != 0 || top != 0)
TransformToPixels(window, left, top,
out pxLeft, out pxTop);
TransformToPixels(window, width, height,
out var pxWidth, out var pxHeight);
User32.MoveWindow(new WindowInteropHelper(window).Handle, pxLeft, pxTop, pxWidth, pxHeight, true);
}
private static void TransformToPixels(this Visual visual,
double unitX,
double unitY,
out int pixelX,
out int pixelY)
{
Matrix matrix;
var source = PresentationSource.FromVisual(visual);
if (source != null)
matrix = source.CompositionTarget.TransformToDevice;
else
using (var src = new HwndSource(new HwndSourceParameters()))
{
matrix = src.CompositionTarget.TransformToDevice;
}
pixelX = (int) Math.Round(matrix.M11 * unitX);
pixelY = (int) Math.Round(matrix.M22 * unitY);
}
public static bool IsForegroundWindowBelongToSelf()
{
var hwnd = User32.GetForegroundWindow();
if (hwnd == IntPtr.Zero)
return false;
User32.GetWindowThreadProcessId(hwnd, out var procId);
return procId == Process.GetCurrentProcess().Id;
}
public static void SetNoactivate(WindowInteropHelper window)
{
User32.SetWindowLong(window.Handle, User32.GWL_EXSTYLE,
User32.GetWindowLong(window.Handle, User32.GWL_EXSTYLE) |
User32.WS_EX_NOACTIVATE);
}
public static void EnableBlur(Window window)
{
var accent = new AccentPolicy();
var accentStructSize = Marshal.SizeOf(accent);
accent.AccentState = AccentState.AccentEnableBlurbehind;
accent.AccentFlags = 2;
accent.GradientColor = 0x99FFFFFF;
var accentPtr = Marshal.AllocHGlobal(accentStructSize);
Marshal.StructureToPtr(accent, accentPtr, false);
var data = new WindowCompositionAttributeData
{
Attribute = WindowCompositionAttribute.WcaAccentPolicy,
SizeOfData = accentStructSize,
Data = accentPtr
};
User32.SetWindowCompositionAttribute(new WindowInteropHelper(window).Handle, ref data);
Marshal.FreeHGlobal(accentPtr);
}
[StructLayout(LayoutKind.Sequential)]
public struct WindowCompositionAttributeData
{
public WindowCompositionAttribute Attribute;
public IntPtr Data;
public int SizeOfData;
}
private enum AccentState
{
AccentDisabled = 0,
AccentEnableGradient = 1,
AccentEnableTransparentgradient = 2,
AccentEnableBlurbehind = 3,
AccentInvalidState = 4
}
[StructLayout(LayoutKind.Sequential)]
private struct AccentPolicy
{
public AccentState AccentState;
public int AccentFlags;
public uint GradientColor;
public readonly int AnimationId;
}
}
}

View File

@@ -0,0 +1,62 @@
// Copyright © 2017 Paddy Xu
//
// This file is part of QuickLook program.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
namespace QuickLook.Common
{
/// <summary>
/// Interface implemented by every QuickLook.Plugin
/// </summary>
public interface IViewer
{
/// <summary>
/// Set the priority of this plugin. A plugin with a higher priority may override one with lower priority.
/// Set this to int.MaxValue for a maximum priority, int.MinValue for minimum.
/// </summary>
int Priority { get; }
/// <summary>
/// Do ont-time job when application starts. You may extract nessessary resource here.
/// </summary>
void Init();
/// <summary>
/// Determine whether this plugin can open this file. Please also check the file header, if applicable.
/// </summary>
/// <param name="path">The full path of the target file.</param>
bool CanHandle(string path);
/// <summary>
/// Do some preparation stuff before the window is showing. Please not do any work that costs a lot of time.
/// </summary>
/// <param name="path">The full path of the target file.</param>
/// <param name="context">A runtime object which allows interaction between this plugin and QuickLook.</param>
void Prepare(string path, ContextObject context);
/// <summary>
/// Start the loading process. During the process a busy indicator will be shown. Finish by setting context.IsBusy to
/// false.
/// </summary>
/// <param name="path">The full path of the target file.</param>
/// <param name="context">A runtime object which allows interaction between this plugin and QuickLook.</param>
void View(string path, ContextObject context);
/// <summary>
/// Release any unmanaged resource here.
/// </summary>
void Cleanup();
}
}

View File

@@ -0,0 +1,40 @@
// Copyright © 2017 Paddy Xu
//
// This file is part of QuickLook program.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace QuickLook.Common.NativeMethods
{
public static class Kernel32
{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll")]
public static extern int GetCurrentPackageFullName(ref uint packageFullNameLength,
[MarshalAs(UnmanagedType.LPWStr)] StringBuilder packageFullName);
[DllImport("kernel32.dll")]
public static extern IntPtr GetCurrentThreadId();
[DllImport("kernel32.dll")]
public static extern bool GetProductInfo(int dwOSMajorVersion, int dwOSMinorVersion, int dwSpMajorVersion,
int dwSpMinorVersion, out uint pdwReturnedProductType);
}
}

View File

@@ -0,0 +1,120 @@
// Copyright © 2017 Paddy Xu
//
// This file is part of QuickLook program.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Text;
using QuickLook.Common.Helpers;
namespace QuickLook.Common.NativeMethods
{
public static class User32
{
public delegate int KeyboardHookProc(int code, int wParam, ref KeyboardHookStruct lParam);
[DllImport("user32.dll")]
public static extern int MoveWindow(IntPtr hWnd, int x, int y, int nWidth, int nHeight,
[MarshalAs(UnmanagedType.Bool)] bool bRepaint);
[DllImport("user32.dll")]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy,
uint uFlags);
[DllImport("user32.dll")]
public static extern IntPtr SetWindowsHookEx(int idHook, KeyboardHookProc callback, IntPtr hInstance,
uint threadId);
[DllImport("user32.dll")]
public static extern bool UnhookWindowsHookEx(IntPtr hInstance);
[DllImport("user32.dll")]
public static extern int CallNextHookEx(IntPtr idHook, int nCode, int wParam, ref KeyboardHookStruct lParam);
[DllImport("user32.dll")]
public static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll")]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
public static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, IntPtr processId);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
[DllImport("user32.dll")]
public static extern IntPtr AttachThreadInput(IntPtr idAttach, IntPtr idAttachTo, bool fAttach);
[DllImport("user32.dll")]
public static extern IntPtr GetFocus();
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll")]
public static extern IntPtr GetParent(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern int SetWindowCompositionAttribute(IntPtr hwnd,
ref WindowHelper.WindowCompositionAttributeData data);
[SuppressMessage("ReSharper", "InconsistentNaming")]
public struct KeyboardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
// ReSharper disable InconsistentNaming
public static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
public static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
public static readonly IntPtr HWND_TOP = new IntPtr(0);
public static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
public const uint SWP_NOSIZE = 0x0001;
public const uint SWP_NOMOVE = 0x0002;
public const uint SWP_NOZORDER = 0x0004;
public const uint SWP_NOREDRAW = 0x0008;
public const uint SWP_NOACTIVATE = 0x0010;
public const uint SWP_DRAWFRAME = 0x0020;
public const uint SWP_FRAMECHANGED = 0x0020;
public const uint SWP_SHOWWINDOW = 0x0040;
public const uint SWP_HIDEWINDOW = 0x0080;
public const uint SWP_NOCOPYBITS = 0x0100;
public const uint SWP_NOOWNERZORDER = 0x0200;
public const uint SWP_NOREPOSITION = 0x0200;
public const uint SWP_NOSENDCHANGING = 0x0400;
public const uint SWP_DEFERERASE = 0x2000;
public const uint SWP_ASYNCWINDOWPOS = 0x4000;
public const int WH_KEYBOARD_LL = 13;
public const int WM_KEYDOWN = 0x100;
public const int WM_KEYUP = 0x101;
public const int WM_SYSKEYDOWN = 0x104;
public const int WM_SYSKEYUP = 0x105;
public const int GWL_EXSTYLE = -20;
public const int WS_EX_NOACTIVATE = 0x08000000;
// ReSharper restore InconsistentNaming
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("QuickLook.Plugin.IViewerPlugin")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("QuickLook.Plugin.IViewerPlugin")]
[assembly: AssemblyCopyright("Copyright © Paddy Xu 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("85fdd6ba-871d-46c8-bd64-f6bb0cb5ea95")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]

View File

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{85FDD6BA-871D-46C8-BD64-F6BB0CB5EA95}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>QuickLook.Common</RootNamespace>
<AssemblyName>QuickLook.Plugin.IViewerPlugin</AssemblyName>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\Build\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\Build\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\GitVersion.cs">
<Link>Properties\GitVersion.cs</Link>
</Compile>
<Compile Include="ContextObject.cs" />
<Compile Include="Helpers\DpiHelper.cs" />
<Compile Include="ExtensionMethods\BitmapExtensions.cs" />
<Compile Include="ExtensionMethods\DispatcherExtensions.cs" />
<Compile Include="ExtensionMethods\EnumerableExtensions.cs" />
<Compile Include="ExtensionMethods\FileExtensions.cs" />
<Compile Include="ExtensionMethods\TypeExtensions.cs" />
<Compile Include="Helpers\FileHelper.cs" />
<Compile Include="IViewer.cs" />
<Compile Include="NativeMethods\Kernel32.cs" />
<Compile Include="Helpers\ProcessHelper.cs" />
<Compile Include="Properties\Annotations.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Helpers\SettingHelper.cs" />
<Compile Include="Helpers\TranslationHelper.cs" />
<Compile Include="NativeMethods\User32.cs" />
<Compile Include="Helpers\WindowHelper.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>