Compare commits

...

12 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
14d1cbe8c7 Complete text selection implementation for MSI info panel
Co-authored-by: emako <24737061+emako@users.noreply.github.com>
2025-07-26 06:43:28 +00:00
copilot-swe-agent[bot]
6cacc139a6 Enable text selection for copying file information values
Co-authored-by: emako <24737061+emako@users.noreply.github.com>
2025-07-26 06:41:17 +00:00
copilot-swe-agent[bot]
8846a84835 Initial plan 2025-07-26 06:31:17 +00:00
dependabot[bot]
d88c8ab8de Bump Magick.NET-Q8-AnyCPU from 14.6.0 to 14.7.0
Some checks failed
MSBuild / build (push) Has been cancelled
MSBuild / publish (push) Has been cancelled
---
updated-dependencies:
- dependency-name: Magick.NET-Q8-AnyCPU
  dependency-version: 14.7.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-24 16:35:58 +08:00
copilot-swe-agent[bot]
a38b7a450a Fix code alignment by adding space to align .Replace method calls
Some checks failed
MSBuild / build (push) Has been cancelled
MSBuild / publish (push) Has been cancelled
Co-authored-by: emako <24737061+emako@users.noreply.github.com>
2025-07-23 23:57:13 +08:00
copilot-swe-agent[bot]
8ad5f39eab Add missing using System.Linq to fix compile error
Co-authored-by: emako <24737061+emako@users.noreply.github.com>
2025-07-23 23:57:13 +08:00
copilot-swe-agent[bot]
83cfd2a3d8 Remove unnecessary Translations.config and simplify RTL detection code
Co-authored-by: emako <24737061+emako@users.noreply.github.com>
2025-07-23 23:57:13 +08:00
copilot-swe-agent[bot]
4840a87858 Add RTL support for markdown files
Co-authored-by: emako <24737061+emako@users.noreply.github.com>
2025-07-23 23:57:13 +08:00
VenusGirl❤
a4d118e11f Update Korean (#1710)
Some checks failed
MSBuild / build (push) Has been cancelled
MSBuild / publish (push) Has been cancelled
2025-07-23 15:07:39 +08:00
ema
79b002c0b3 Unified changelog style
Some checks failed
MSBuild / build (push) Has been cancelled
MSBuild / publish (push) Has been cancelled
2025-07-20 23:00:53 +08:00
ema
b26575581a Update changelog for 4.1.1 release 2025-07-20 22:55:20 +08:00
ema
8c95a42a64 Refactor tray icon to use TrayIconHost 2025-07-20 21:54:32 +08:00
23 changed files with 273 additions and 433 deletions

View File

@@ -1,3 +1,18 @@
## 4.1.1
- Add built-in ThumbnailViewer plugin [#1662](https://github.com/QL-Win/QuickLook/issues/1662)
- Add built-in HelixViewer for 3d models [#1662](https://github.com/QL-Win/QuickLook/issues/1662)
- Add FBX model support using AssimpNet [#1479](https://github.com/QL-Win/QuickLook/issues/1479)
- Add `SVGA` and `Lottie Files` animation preview support
- Add MathJax inline math support to Markdown [#1640](https://github.com/QL-Win/QuickLook/issues/1640)
- Add `SubRip Subtitle (.srt) files`, `Protobuf`, `NSIS`, `.gitmodules`, `.dotsettings`, `.gitignore`, `.gitattributes`, `Markdown`, `reStructuredText`, `simple QML syntax`, `.env`, `Configuration (.conf;.config;.cfg)` highlighting [#1002](https://github.com/QL-Win/QuickLook/issues/1002)
- Add dark mode highlighting for `PowerShell`, `Registry`, `C`, `C++`, `Java`, `Rust`, `SQL`, `Ruby`, `R`, `PHP`, `Pascal`, `Objective-C`, `Lisp`, `Kotlin`, `Erlang`, `Dart`, `Swift`, `VisualSolution`, `CMake`
- Add `MakefileDetector`, `CMakeListsDetector for CMakeLists.txt`, `DockerfileDetector`, `HostsDetector for hosts` for text viewer
- Improve QuickLook initialization speed
- Optimize JSONDetector with Span
- Set RichTextBox background to transparent
- Revert Add Sandbox detection from 4.1.0 which will call crash
## 4.1.0
- Add built-in AppViewer plugin for `.msi`, `.appx`, `.msix`, `.wgt`, `.wgtu`, `.apk`, `.ipa`, `.hap`, `.deb`, `.dmg`, `.appimage`, `.rpm`, `.aab`
@@ -34,15 +49,11 @@
## 4.0.2
[Major Change]
- Support .pcx image [#1638](https://github.com/QL-Win/QuickLook/issues/1638)
- Improve PE parsing with extended buffer size
- Fix flickering [#1628](https://github.com/QL-Win/QuickLook/issues/1628)
- Fix DpiAwareness for PerMonitor [#1626](https://github.com/QL-Win/QuickLook/issues/1626)
[Small Change]
- Hide PEViewer Title just like InfoPanel
- Avoid audio cover null exception in xaml
@@ -59,8 +70,8 @@
## 4.0.0
[Common]
- Add built-in PE viewer plugin
- Add built-in font viewer plugin
- Update translations
- Update dependent packages
- Add support for Multi Commander
@@ -75,53 +86,27 @@
- Fix plugin installer description length limit
- Prevent crash when WMI fails [#1379](https://github.com/QL-Win/QuickLook/issues/1379)
- Show toast when "Prevent Closing" cannot be cancelled [#1368](https://github.com/QL-Win/QuickLook/issues/1368)
[ImageViewer]
- Add support for multi-layer GIMP .xcf files [#1224](https://github.com/QL-Win/QuickLook/issues/1224)
- Fix .xcf file extension check [#1229](https://github.com/QL-Win/QuickLook/issues/1229)
- Fix HEIC preview rendering [#1470](https://github.com/QL-Win/QuickLook/issues/1470)
- Add support for .qoi, .icns, .dds, .svgz, .psb, .cur, and .ani formats
- Improve animated WebP support (x64 only) [#1024](https://github.com/QL-Win/QuickLook/issues/1024) [#1324](https://github.com/QL-Win/QuickLook/issues/1324)
- Improve GIF decoding performance [#993](https://github.com/QL-Win/QuickLook/issues/993)
- Add copy button to image viewer [#1399](https://github.com/QL-Win/QuickLook/issues/1399)
- Fix SVG rendering error [#1430](https://github.com/QL-Win/QuickLook/issues/1430)
[TextViewer]
- Add double-encoding detection [#471](https://github.com/QL-Win/QuickLook/issues/471) [#600](https://github.com/QL-Win/QuickLook/issues/600) ...
- Improve dark mode rendering
- Catch exceptions from XSHD loader
- Add syntax highlighting for shell scripts [#668](https://github.com/QL-Win/QuickLook/issues/668)
- Add dark mode support for C# syntax highlighting
[ArchiveViewer]
- Improve support for comic archive formats [#1276](https://github.com/QL-Win/QuickLook/issues/1276)
- Redesign file list with Fluent UI
[CsvViewer]
- Change default background color to blue
- Fix issue with non-UTF8 CSV encoding
[MarkdownViewer]
- Improve rendering and stability
[PDFViewer]
- Add support for password-protected PDFs [#155](https://github.com/QL-Win/QuickLook/issues/155)
- Enable auto-resizing of the viewer window
[VideoViewer]
- Fix audio cover parsing error for multiple embedded images
- Add lyric (.lrc) support for audio files [#1506](https://github.com/QL-Win/QuickLook/issues/1506)
- Add support for .mid audio format [#931](https://github.com/QL-Win/QuickLook/issues/931)
- Fix time label overflow in long videos
[PEViewer & FontViewer]
- Add built-in PE viewer plugin
- Add built-in font viewer plugin
- Add support for multi-layer GIMP .xcf files [#1224](https://github.com/QL-Win/QuickLook/issues/1224) for ImageViewer
- Fix .xcf file extension check [#1229](https://github.com/QL-Win/QuickLook/issues/1229) for ImageViewer
- Fix HEIC preview rendering [#1470](https://github.com/QL-Win/QuickLook/issues/1470) for ImageViewer
- Add support for .qoi, .icns, .dds, .svgz, .psb, .cur, and .ani formats for ImageViewer
- Improve animated WebP support (x64 only) [#1024](https://github.com/QL-Win/QuickLook/issues/1024) [#1324](https://github.com/QL-Win/QuickLook/issues/1324) for ImageViewer
- Improve GIF decoding performance [#993](https://github.com/QL-Win/QuickLook/issues/993) for ImageViewer
- Add copy button to image viewer [#1399](https://github.com/QL-Win/QuickLook/issues/1399) for ImageViewer
- Fix SVG rendering error [#1430](https://github.com/QL-Win/QuickLook/issues/1430) for ImageViewer
- Add double-encoding detection [#471](https://github.com/QL-Win/QuickLook/issues/471) [#600](https://github.com/QL-Win/QuickLook/issues/600) for TextViewer
- Improve dark mode rendering for TextViewer
- Catch exceptions from XSHD loader for TextViewer
- Add syntax highlighting for shell scripts [#668](https://github.com/QL-Win/QuickLook/issues/668) for TextViewer
- Add dark mode support for C# syntax highlighting for TextViewer
- Improve support for comic archive formats [#1276](https://github.com/QL-Win/QuickLook/issues/1276) for ArchiveViewer
- Redesign file list with Fluent UI for ArchiveViewer
- Change default background color to blue for CsvViewer
- Fix issue with non-UTF8 CSV encoding for CsvViewer
- Improve rendering and stability for MarkdownViewer
- Add support for password-protected PDFs [#155](https://github.com/QL-Win/QuickLook/issues/155) for PDFViewer
- Enable auto-resizing of the viewer window for PDFViewer
- Fix audio cover parsing error for multiple embedded images for VideoViewer
- Add lyric (.lrc) support for audio files [#1506](https://github.com/QL-Win/QuickLook/issues/1506) for VideoViewer
- Add support for .mid audio format [#931](https://github.com/QL-Win/QuickLook/issues/931) for VideoViewer
- Fix time label overflow in long videos for VideoViewer

View File

@@ -89,6 +89,7 @@
Padding="3"
FontSize="19"
FontWeight="SemiBold"
IsTextSelectionEnabled="True"
LineHeight="25"
TextTrimming="CharacterEllipsis"
TextWrapping="Wrap">
@@ -110,6 +111,7 @@
Margin="8,0,0,0"
Padding="3"
Foreground="{DynamicResource WindowTextForegroundAlternative}"
IsTextSelectionEnabled="True"
Text="Searching..."
TextTrimming="CharacterEllipsis"
TextWrapping="Wrap" />

View File

@@ -84,6 +84,7 @@
Padding="3"
FontSize="19"
FontWeight="SemiBold"
IsTextSelectionEnabled="True"
LineHeight="25"
TextTrimming="CharacterEllipsis"
TextWrapping="Wrap">
@@ -105,6 +106,7 @@
Margin="8,0,0,0"
Padding="3"
Foreground="{DynamicResource WindowTextForegroundAlternative}"
IsTextSelectionEnabled="True"
Text="Searching..."
TextTrimming="CharacterEllipsis"
TextWrapping="Wrap" />
@@ -121,6 +123,7 @@
Margin="8,0,0,0"
Padding="3"
Foreground="{DynamicResource WindowTextForegroundAlternative}"
IsTextSelectionEnabled="True"
Text="Searching..."
TextTrimming="CharacterEllipsis"
TextWrapping="Wrap" />
@@ -137,6 +140,7 @@
Margin="8,0,0,0"
Padding="3"
Foreground="{DynamicResource WindowTextForegroundAlternative}"
IsTextSelectionEnabled="True"
Text="Searching..."
TextTrimming="CharacterEllipsis"
TextWrapping="Wrap" />
@@ -153,6 +157,7 @@
Margin="8,0,0,0"
Padding="3"
Foreground="{DynamicResource WindowTextForegroundAlternative}"
IsTextSelectionEnabled="True"
Text="Calculating size..." />
<!-- Last Modified -->
<TextBlock x:Name="modDateTitle"
@@ -167,6 +172,7 @@
Margin="8,0,0,0"
Padding="3"
Foreground="{DynamicResource WindowTextForegroundAlternative}"
IsTextSelectionEnabled="True"
Text="Searching..."
TextTrimming="CharacterEllipsis" />
<!-- Capabilities -->

View File

@@ -110,6 +110,7 @@
Margin="8,0,0,0"
Padding="3"
Foreground="{DynamicResource WindowTextForegroundAlternative}"
IsTextSelectionEnabled="True"
Text="Searching..."
TextTrimming="CharacterEllipsis"
TextWrapping="Wrap" />

View File

@@ -98,6 +98,7 @@
Margin="8,0,0,0"
Padding="3"
Foreground="{DynamicResource WindowTextForegroundAlternative}"
IsTextSelectionEnabled="True"
Text="Searching..."
TextTrimming="CharacterEllipsis"
TextWrapping="Wrap" />

View File

@@ -34,6 +34,39 @@
<TERMINAL>Terminal</TERMINAL>
<VENDOR>Vendor</VENDOR>
</en>
<ko>
<PRODUCT_VERSION>제품 버전</PRODUCT_VERSION>
<PRODUCT_NAME>제품 이름</PRODUCT_NAME>
<MANUFACTURER>제조업체</MANUFACTURER>
<TOTAL_SIZE>전체 크기</TOTAL_SIZE>
<LAST_MODIFIED>최종 수정됨</LAST_MODIFIED>
<PUBLISHER>발행자</PUBLISHER>
<CAPABILITIES>성능</CAPABILITIES>
<ABI>ABIs</ABI>
<APP_NAME>응용 프로그램</APP_NAME>
<APP_VERSION>버전</APP_VERSION>
<APP_VERSION_NAME>버전 이름</APP_VERSION_NAME>
<APP_VERSION_CODE>버전 코드</APP_VERSION_CODE>
<PERMISSIONS>권한</PERMISSIONS>
<PACKAGE_NAME>패키지 이름</PACKAGE_NAME>
<APP_MIN_SDK_VERSION>최소 SDK 버전</APP_MIN_SDK_VERSION>
<APP_TARGET_SDK_VERSION>대상 SDK 버전</APP_TARGET_SDK_VERSION>
<APP_MIN_OS_VERSION>최소 OS 버전</APP_MIN_OS_VERSION>
<APP_TARGET_OS_VERSION>대상 OS 버전</APP_TARGET_OS_VERSION>
<DEVICE_FAMILY>장치 제품군</DEVICE_FAMILY>
<BUNDLE_NAME>번들 이름</BUNDLE_NAME>
<DEVICE_TYPES>장치 유형</DEVICE_TYPES>
<APP_MIN_API_VERSION>최소 API 버전</APP_MIN_API_VERSION>
<APP_TARGET_API_VERSION>대상 API 버전</APP_TARGET_API_VERSION>
<COMPILE_SDK_VERSION>SDK 버전 컴파일</COMPILE_SDK_VERSION>
<ARCHITECTURE>아키텍쳐</ARCHITECTURE>
<MAINTAINER>유지 관리자</MAINTAINER>
<DESCRIPTION>설명</DESCRIPTION>
<ENVIRONMENT>환경</ENVIRONMENT>
<TYPE>유형</TYPE>
<TERMINAL>터미널</TERMINAL>
<VENDOR>공급업체</VENDOR>
</ko>
<pt-BR>
<PRODUCT_VERSION>Versão do produto</PRODUCT_VERSION>
<PRODUCT_NAME>Nome do produto</PRODUCT_NAME>

View File

@@ -7,6 +7,12 @@
<ConfirmDeleteText>Are you sure you want to permanently delete these {0} item(s)?</ConfirmDeleteText>
<RecycleBinSizeText>Total size {0}, {1} items</RecycleBinSizeText>
</en>
<ko>
<RecycleBinEmptyText>휴지통이 비어 있습니다</RecycleBinEmptyText>
<RecycleBinButton>휴지통 비우기</RecycleBinButton>
<ConfirmDeleteText>{0}개 항목을 영구적으로 삭제하시겠습니까?</ConfirmDeleteText>
<RecycleBinSizeText>전체 크기 {0}, {1}개 항목</RecycleBinSizeText>
</ko>
<zh-CN>
<RecycleBinEmptyText>回收站是空的</RecycleBinEmptyText>
<RecycleBinButton>清空回收站</RecycleBinButton>
@@ -25,12 +31,6 @@
<ConfirmDeleteText>これらの {0} 項目を完全に削除してもよろしいですか?</ConfirmDeleteText>
<RecycleBinSizeText>合計サイズ {0}、{1} 項目</RecycleBinSizeText>
</ja>
<ko>
<RecycleBinEmptyText>휴지통이 비어 있습니다</RecycleBinEmptyText>
<RecycleBinButton>휴지통 비우기</RecycleBinButton>
<ConfirmDeleteText>{0}개의 항목을 영구적으로 삭제하시겠습니까?</ConfirmDeleteText>
<RecycleBinSizeText>총 크기 {0}, 총 {1}개 항목</RecycleBinSizeText>
</ko>
<fr>
<RecycleBinEmptyText>La corbeille est vide</RecycleBinEmptyText>
<RecycleBinButton>Vider la corbeille</RecycleBinButton>

View File

@@ -7,6 +7,12 @@
<FORMAT_PROFILE>Format Profile</FORMAT_PROFILE>
<NAME>Name</NAME>
</en>
<ko>
<TOTAL_SIZE>전체 크기</TOTAL_SIZE>
<FORMAT>형식</FORMAT>
<FORMAT_PROFILE>형식 프로필</FORMAT_PROFILE>
<NAME>이름</NAME>
</ko>
<pt-BR>
<TOTAL_SIZE>Tamanho total</TOTAL_SIZE>
<FORMAT>Formato</FORMAT>

View File

@@ -4,6 +4,9 @@
<en>
<SAMPLE_TEXT>The quick brown fox jumped over the lazy dog. 1234567890</SAMPLE_TEXT>
</en>
<ko>
<SAMPLE_TEXT>지금 이 순간, 나의 아름다움은 가장 빛난다 - 비너스걸. 1234567890</SAMPLE_TEXT>
</ko>
<zh-CN>
<SAMPLE_TEXT>Innovation in China 中国智造,惠及全球 0123456789</SAMPLE_TEXT>
</zh-CN>

View File

@@ -4,6 +4,9 @@
<en>
<WEBVIEW2_NOT_AVAILABLE>Viewing this file requires Microsoft Edge WebView2 to be installed.&#10;Click here to download it.</WEBVIEW2_NOT_AVAILABLE>
</en>
<ko>
<WEBVIEW2_NOT_AVAILABLE>이 파일을 보려면 Microsoft Edge WebView2를 설치해야 합니다.&#10;여기를 클릭하여 다운로드하세요.</WEBVIEW2_NOT_AVAILABLE>
</ko>
<de>
<WEBVIEW2_NOT_AVAILABLE>Für das Anzeigen dieses Dateityps wird MS Edge WebView2 benötigt.&#10;Hier klicken zum Downloaden.</WEBVIEW2_NOT_AVAILABLE>
</de>
@@ -13,9 +16,6 @@
<ja>
<WEBVIEW2_NOT_AVAILABLE>このファイルを閲覧するには、Microsoft Edge WebView2 がインストールされている必要があります。&#10;ここをクリックしてダウンロードを開始する。</WEBVIEW2_NOT_AVAILABLE>
</ja>
<ko-KR>
<WEBVIEW2_NOT_AVAILABLE>이 파일을 표시하려면 Microsoft Edge WebView2가 필요합니다.&#10;여기를 클릭해서 다운로드 하세요.</WEBVIEW2_NOT_AVAILABLE>
</ko-KR>
<zh-CN>
<WEBVIEW2_NOT_AVAILABLE>查看此文件需要安装 Microsoft Edge WebView2。&#10;点击这里开始下载。</WEBVIEW2_NOT_AVAILABLE>
</zh-CN>

View File

@@ -59,7 +59,7 @@
<PackageReference Include="QuickLook.ImageGlass.WebP" Version="1.4.0">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Magick.NET-Q8-AnyCPU" Version="14.6.0">
<PackageReference Include="Magick.NET-Q8-AnyCPU" Version="14.7.0">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3351.48">

View File

@@ -16,10 +16,12 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using Microsoft.Web.WebView2.Core;
using QuickLook.Common.Helpers;
using QuickLook.Plugin.HtmlViewer;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -78,7 +80,21 @@ public class MarkdownPanel : WebpagePanel
var content = encoding.GetString(bytes);
var template = ReadString("/md2html.html");
var html = template.Replace("{{content}}", content);
// Support automatic RTL for markdown files
bool isRtl = false;
if (CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft)
{
string isSupportRTL = TranslationHelper.Get("IsSupportRTL",
failsafe: bool.TrueString,
domain: Assembly.GetExecutingAssembly().GetName().Name);
if (bool.TrueString.Equals(isSupportRTL, StringComparison.OrdinalIgnoreCase))
isRtl = true;
}
var html = template.Replace("{{content}}", content)
.Replace("{{rtl}}", isRtl ? "rtl" : "ltr");
return html;
}

View File

@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html dir="{{rtl}}">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
@@ -144,6 +144,34 @@
cursor: ew-resize;
user-select: none;
}
/* RTL support */
html[dir="rtl"] .container {
flex-direction: row-reverse;
}
html[dir="rtl"] #toc {
right: 0;
left: auto;
}
html[dir="rtl"] .table-of-contents a {
border-right: 2px solid transparent;
border-left: none;
margin-right: -1em;
margin-left: 0;
padding-right: calc(1em - 2px);
padding-left: 0;
}
html[dir="rtl"] .table-of-contents .active {
border-right: 2px solid var(--fgColor-accent);
border-left: none;
margin-right: -1em;
margin-left: 0;
padding-right: calc(1em - 2px);
padding-left: 0;
}
</style>
<textarea id="text-input" style="display: none">{{content}}</textarea>
@@ -337,6 +365,21 @@
if (e.code === "Space") {
e.preventDefault();
}
// Support keyboard shortcuts for RTL and LTR text direction
// RTL: Ctrl + RShift
// LTR: Ctrl + LShift
if ((e.ctrlKey || e.metaKey)) {
if (e.shiftKey && e.location === KeyboardEvent.DOM_KEY_LOCATION_RIGHT) {
// Right Shift + Ctrl: RTL
document.documentElement.setAttribute('dir', 'rtl');
e.preventDefault();
} else if (e.shiftKey && e.location === KeyboardEvent.DOM_KEY_LOCATION_LEFT) {
// Left Shift + Ctrl: LTR
document.documentElement.setAttribute('dir', 'ltr');
e.preventDefault();
}
}
});
});
</script>

View File

@@ -7,6 +7,12 @@
<ConfirmDeleteText>Are you sure you want to permanently delete these {0} item(s)?</ConfirmDeleteText>
<RecycleBinSizeText>Total size {0}, {1} items</RecycleBinSizeText>
</en>
<ko>
<RecycleBinEmptyText>휴지통이 비어 있습니다</RecycleBinEmptyText>
<RecycleBinButton>휴지통 비우기</RecycleBinButton>
<ConfirmDeleteText>{0}개 항목을 영구적으로 삭제하시겠습니까?</ConfirmDeleteText>
<RecycleBinSizeText>전체 크기 {0}, {1}개 항목</RecycleBinSizeText>
</ko>
<zh-CN>
<RecycleBinEmptyText>回收站是空的</RecycleBinEmptyText>
<RecycleBinButton>清空回收站</RecycleBinButton>

View File

@@ -8,6 +8,13 @@
<BTN_OpenFile>Open File</BTN_OpenFile>
<BTN_Cancel>Cancel</BTN_Cancel>
</en>
<ko>
<PW_Title>비밀번호 입력</PW_Title>
<Pw_Hint>이 파일은 비밀번호로 보호되어 있습니다. 파일을 열려면 비밀번호를 입력하세요.</Pw_Hint>
<PW_Error>비밀번호 확인</PW_Error>
<BTN_OpenFile>파일 열기</BTN_OpenFile>
<BTN_Cancel>취소</BTN_Cancel>
</ko>
<ja-JP>
<PW_Title>パスワード入力</PW_Title>
<Pw_Hint>このファイルではパスワードで保護されています。ファイルを開くにはパスワードを入力してください。</Pw_Hint>

View File

@@ -72,6 +72,7 @@
Padding="3"
FontSize="19"
FontWeight="SemiBold"
IsTextSelectionEnabled="True"
LineHeight="25"
TextTrimming="CharacterEllipsis"
TextWrapping="Wrap">
@@ -107,6 +108,7 @@
Margin="8,0,0,0"
Padding="3"
Foreground="{DynamicResource WindowTextForegroundAlternative}"
IsTextSelectionEnabled="True"
Text="Calculating size..." />
<!-- File Version -->
<TextBlock x:Name="fileVersionTitle"
@@ -121,6 +123,7 @@
Margin="8,0,0,0"
Padding="3"
Foreground="{DynamicResource WindowTextForegroundAlternative}"
IsTextSelectionEnabled="True"
Text="Searching..."
TextTrimming="CharacterEllipsis" />
<!-- Product Version -->
@@ -136,6 +139,7 @@
Margin="8,0,0,0"
Padding="3"
Foreground="{DynamicResource WindowTextForegroundAlternative}"
IsTextSelectionEnabled="True"
Text="Searching..."
TextTrimming="CharacterEllipsis"
TextWrapping="Wrap" />

View File

@@ -6,6 +6,11 @@
<FILE_VERSION>File Version</FILE_VERSION>
<PRODUCT_VERSION>Product Version</PRODUCT_VERSION>
</en>
<ko>
<TOTAL_SIZE>전체 크기</TOTAL_SIZE>
<FILE_VERSION>파일 버전</FILE_VERSION>
<PRODUCT_VERSION>제품 버전</PRODUCT_VERSION>
</ko>
<pt-BR>
<TOTAL_SIZE>Tamanho total</TOTAL_SIZE>
<FILE_VERSION>Versão do arquivo</FILE_VERSION>

View File

@@ -39,9 +39,11 @@
<Editor_Copy>コピー</Editor_Copy>
<Editor_SelectAll>すべて選択</Editor_SelectAll>
</ja-JP>
<ko-KR>
<Editor_FontFamily>Consolas,Malgun Gothic,Batang</Editor_FontFamily>
</ko-KR>
<ko>
<Editor_FontFamily>Consolas,Malgun Gothic,Gulim</Editor_FontFamily>
<Editor_Copy>복사</Editor_Copy>
<Editor_SelectAll>모두 선택</Editor_SelectAll>
</ko>
<nb-NO>
<Editor_FontFamily>Consolas</Editor_FontFamily>
</nb-NO>

View File

@@ -213,9 +213,6 @@ public partial class App : Application
// Initialize MessageBox patching
bool modernMessageBox = SettingHelper.Get("ModernMessageBox", true, "QuickLook");
if (modernMessageBox) MessageBoxPatcher.Initialize();
// Initialize TrayIcon patching
bool modernTrayIcon = SettingHelper.Get("ModernTrayIcon", true, "QuickLook");
if (modernTrayIcon) TrayIconPatcher.Initialize();
// Set initial theme based on system settings
ThemeManager.Apply(OSThemeHelper.AppsUseDarkTheme() ? ApplicationTheme.Dark : ApplicationTheme.Light);
@@ -223,6 +220,9 @@ public partial class App : Application
ThemeManager.Apply(OSThemeHelper.AppsUseDarkTheme() ? ApplicationTheme.Dark : ApplicationTheme.Light);
UxTheme.ApplyPreferredAppMode();
// Initialize TrayIcon
_ = TrayIconManager.GetInstance();
base.OnStartup(e);
}
@@ -240,7 +240,7 @@ public partial class App : Application
CheckUpdate();
RunListener(e);
// first instance: run and preview this file
// First instance: run and preview this file
if (e.Args.Any() && (Directory.Exists(e.Args.First()) || File.Exists(e.Args.First())))
PipeServerManager.SendMessage(PipeMessages.Toggle, e.Args.First());
}
@@ -318,12 +318,12 @@ public partial class App : Application
if (isFirst)
return true;
// second instance: preview this file
// Second instance: preview this file
if (args.Any() && (Directory.Exists(args.First()) || File.Exists(args.First())))
{
PipeServerManager.SendMessage(PipeMessages.Toggle, args.First(), [.. args.Skip(1)]);
}
// second instance: duplicate
// Second instance: duplicate
else
MessageBox.Show(TranslationHelper.Get("APP_SECOND_TEXT"), TranslationHelper.Get("APP_SECOND"),
MessageBoxButton.OK, MessageBoxImage.Information);

View File

@@ -1,298 +0,0 @@
// Copyright © 2017-2025 QL-Win Contributors
//
// 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 HarmonyLib;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Windows.Forms;
namespace QuickLook.Helpers;
public static class TrayIconPatcher
{
private static readonly Harmony Harmony = new("com.quicklook.trayicon.patch");
public static void Initialize()
{
var targetMethod = typeof(NotifyIcon).GetMethod("ShowContextMenu", BindingFlags.NonPublic | BindingFlags.Instance);
if (targetMethod != null)
{
_ = Harmony.Patch(targetMethod, transpiler: new HarmonyMethod(typeof(TrayIconPatcher).GetMethod(nameof(ShowContextMenuTranspiler))));
}
}
public static void ShowContextMenu(this NotifyIcon icon)
{
var targetMethod = typeof(NotifyIcon).GetMethod("ShowContextMenu", BindingFlags.NonPublic | BindingFlags.Instance);
targetMethod?.Invoke(icon, []);
}
/// <summary>
/// We need to change the NotifyIcon.ShowContextMenu to use TPM_RIGHTBUTTON instead of TPM_VERTICAL.
/// private void ShowContextMenu()
/// {
/// if (contextMenu != null || contextMenuStrip != null)
/// {
/// NativeMethods.POINT pOINT = new NativeMethods.POINT();
/// UnsafeNativeMethods.GetCursorPos(pOINT);
/// UnsafeNativeMethods.SetForegroundWindow(new HandleRef(window, window.Handle));
/// if (contextMenu != null)
/// {
/// contextMenu.OnPopup(EventArgs.Empty);
/// SafeNativeMethods.TrackPopupMenuEx(new HandleRef(contextMenu, contextMenu.Handle), 72, pOINT.x, pOINT.y, new HandleRef(window, window.Handle), null);
/// UnsafeNativeMethods.PostMessage(new HandleRef(window, window.Handle), 0, IntPtr.Zero, IntPtr.Zero);
/// }
/// else if (contextMenuStrip != null)
/// {
/// contextMenuStrip.ShowInTaskbar(pOINT.x, pOINT.y);
/// }
/// }
/// }
/// ---
/// Opcode: ldarg.0, Operand:
/// Opcode: ldfld, Operand: System.Windows.Forms.ContextMenu contextMenu
/// Opcode: brtrue.s, Operand: System.Reflection.Emit.Label
/// Opcode: ldarg.0, Operand:
/// Opcode: ldfld, Operand: System.Windows.Forms.ContextMenuStrip contextMenuStrip
/// Opcode: brfalse, Operand: System.Reflection.Emit.Label
/// Opcode: newobj, Operand: Void.ctor()
/// Opcode: stloc.0, Operand:
/// Opcode: ldloc.0, Operand:
/// Opcode: call, Operand: Boolean GetCursorPos(POINT)
/// Opcode: pop, Operand:
/// Opcode: ldarg.0, Operand:
/// Opcode: ldfld, Operand: NotifyIconNativeWindow window
/// Opcode: ldarg.0, Operand:
/// Opcode: ldfld, Operand: NotifyIconNativeWindow window
/// Opcode: callvirt, Operand: IntPtr get_Handle()
/// Opcode: newobj, Operand: Void.ctor(System.Object, IntPtr)
/// Opcode: call, Operand: Boolean SetForegroundWindow(System.Runtime.InteropServices.HandleRef)
/// Opcode: pop, Operand:
/// Opcode: ldarg.0, Operand:
/// Opcode: ldfld, Operand: System.Windows.Forms.ContextMenu contextMenu
/// Opcode: brfalse.s, Operand: System.Reflection.Emit.Label
/// Opcode: ldarg.0, Operand:
/// Opcode: ldfld, Operand: System.Windows.Forms.ContextMenu contextMenu
/// Opcode: ldsfld, Operand: System.EventArgs Empty
/// Opcode: callvirt, Operand: Void OnPopup(System.EventArgs)
/// Opcode: ldarg.0, Operand:
/// Opcode: ldfld, Operand: System.Windows.Forms.ContextMenu contextMenu
/// Opcode: ldarg.0, Operand:
/// Opcode: ldfld, Operand: System.Windows.Forms.ContextMenu contextMenu
/// Opcode: callvirt, Operand: IntPtr get_Handle()
/// Opcode: newobj, Operand: Void.ctor(System.Object, IntPtr)
/// Opcode: ldc.i4.s, Operand: 72
/// Opcode: ldloc.0, Operand:
/// Opcode: ldfld, Operand: Int32 x
/// Opcode: ldloc.0, Operand:
/// Opcode: ldfld, Operand: Int32 y
/// Opcode: ldarg.0, Operand:
/// Opcode: ldfld, Operand: NotifyIconNativeWindow window
/// Opcode: ldarg.0, Operand:
/// Opcode: ldfld, Operand: NotifyIconNativeWindow window
/// Opcode: callvirt, Operand: IntPtr get_Handle()
/// Opcode: newobj, Operand: Void.ctor(System.Object, IntPtr)
/// Opcode: ldnull, Operand:
/// Opcode: call, Operand: Boolean TrackPopupMenuEx(System.Runtime.InteropServices.HandleRef, Int32, Int32, Int32, System.Runtime.InteropServices.HandleRef, TPMPARAMS)
/// Opcode: pop, Operand:
/// Opcode: ldarg.0, Operand:
/// Opcode: ldfld, Operand: NotifyIconNativeWindow window
/// Opcode: ldarg.0, Operand:
/// Opcode: ldfld, Operand: NotifyIconNativeWindow window
/// Opcode: callvirt, Operand: IntPtr get_Handle()
/// Opcode: newobj, Operand: Void.ctor(System.Object, IntPtr)
/// Opcode: ldc.i4.0, Operand:
/// Opcode: ldsfld, Operand: IntPtr Zero
/// Opcode: ldsfld, Operand: IntPtr Zero
/// Opcode: call, Operand: Boolean PostMessage(System.Runtime.InteropServices.HandleRef, Int32, IntPtr, IntPtr)
/// Opcode: pop, Operand:
/// Opcode: ret, Operand:
/// Opcode: ldarg.0, Operand:
/// Opcode: ldfld, Operand: System.Windows.Forms.ContextMenuStrip contextMenuStrip
/// Opcode: brfalse.s, Operand: System.Reflection.Emit.Label
/// Opcode: ldarg.0, Operand:
/// Opcode: ldfld, Operand: System.Windows.Forms.ContextMenuStrip contextMenuStrip
/// Opcode: ldloc.0, Operand:
/// Opcode: ldfld, Operand: Int32 x
/// Opcode: ldloc.0, Operand:
/// Opcode: ldfld, Operand: Int32 y
/// Opcode: callvirt, Operand: Void ShowInTaskbar(Int32, Int32)
/// Opcode: ret, Operand:
/// </summary>
/// <param name="instructions"></param>
/// <returns></returns>
[HarmonyTranspiler]
public static IEnumerable<CodeInstruction> ShowContextMenuTranspiler(IEnumerable<CodeInstruction> instructions)
{
try
{
var codes = instructions.ToArray();
if (Debugger.IsAttached)
{
// Test code to print the IL codes
foreach (var code in codes)
{
Debug.WriteLine($"Opcode: {code.opcode}, Operand: {code.operand}");
}
}
// How to change source code for proxy:
// from SafeNativeMethods.TrackPopupMenuEx(new HandleRef(contextMenu, contextMenu.Handle), 72, pOINT.x, pOINT.y, new HandleRef(window, window.Handle), null);
// to SafeNativeMethods.TrackPopupMenuEx(new HandleRef(contextMenu, contextMenu.Handle), 66, pOINT.x, pOINT.y, new HandleRef(window, window.Handle), null);
// [TrackPopupMenuEx] uFlags: A set of flags that determine how the menu behaves.
// The number 72 in binary is 0100 1000. Breaking it down:
// * TPM_VERTICAL(0x0040)
// * TPM_RIGHTALIGN(0x0008)
// The number 64 in binary is 0100 0000. Breaking it down:
// * TPM_VERTICAL(0x0040)
// * TPM_LEFTALIGN(0x0000)
const sbyte sourceFlag = (sbyte)(TrackPopupMenuFlags.TPM_VERTICAL | TrackPopupMenuFlags.TPM_RIGHTALIGN);
const sbyte targetFlag = (sbyte)(TrackPopupMenuFlags.TPM_VERTICAL | TrackPopupMenuFlags.TPM_LEFTALIGN);
for (int i = 0; i < codes.Length; i++)
{
if (codes[i].opcode == OpCodes.Ldc_I4_S && (sbyte)codes[i].operand == sourceFlag)
{
codes[i].operand = targetFlag;
break;
}
}
return codes;
}
catch
{
// No fallback needed in this case
}
return instructions;
}
/// <summary>
/// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-trackpopupmenuex
/// </summary>
[Flags]
private enum TrackPopupMenuFlags : uint
{
/// <summary>
/// The user can select menu items with only the left mouse button.
/// </summary>
TPM_LEFTBUTTON = 0x0000,
/// <summary>
/// The user can select menu items with both the left and right mouse buttons.
/// </summary>
TPM_RIGHTBUTTON = 0x0002,
/// <summary>
/// Positions the shortcut menu so that its left side is aligned with the coordinate specified by the x parameter.
/// </summary>
TPM_LEFTALIGN = 0x0000,
/// <summary>
/// Centers the shortcut menu horizontally relative to the coordinate specified by the x parameter.
/// </summary>
TPM_CENTERALIGN = 0x0004,
/// <summary>
/// Positions the shortcut menu so that its right side is aligned with the coordinate specified by the x parameter.
/// </summary>
TPM_RIGHTALIGN = 0x0008,
/// <summary>
/// Positions the shortcut menu so that its top side is aligned with the coordinate specified by the y parameter.
/// </summary>
TPM_TOPALIGN = 0x0000,
/// <summary>
/// Centers the shortcut menu vertically relative to the coordinate specified by the y parameter.
/// </summary>
TPM_VCENTERALIGN = 0x0010,
/// <summary>
/// Positions the shortcut menu so that its bottom side is aligned with the coordinate specified by the y parameter.
/// </summary>
TPM_BOTTOMALIGN = 0x0020,
/// <summary>
/// TPM_HORIZONTAL
/// </summary>
TPM_HORIZONTAL = 0x0000,
/// <summary>
/// TPM_VERTICAL
/// </summary>
TPM_VERTICAL = 0x0040,
/// <summary>
/// The function does not send notification messages when the user clicks a menu item.
/// </summary>
TPM_NONOTIFY = 0x0080,
/// <summary>
/// The function returns the menu item identifier of the user's selection in the return value.
/// </summary>
TPM_RETURNCMD = 0x0100,
/// <summary>
/// TPM_RECURSE
/// </summary>
TPM_RECURSE = 0x0001,
/// <summary>
/// Animates the menu from left to right.
/// </summary>
TPM_HORPOSANIMATION = 0x0400,
/// <summary>
/// Animates the menu from right to left.
/// </summary>
TPM_HORNEGANIMATION = 0x0800,
/// <summary>
/// Animates the menu from top to bottom.
/// </summary>
TPM_VERPOSANIMATION = 0x1000,
/// <summary>
/// Animates the menu from bottom to top.
/// </summary>
TPM_VERNEGANIMATION = 0x2000,
/// <summary>
/// Displays menu without animation.
/// </summary>
TPM_NOANIMATION = 0x4000,
/// <summary>
/// TPM_LAYOUTRTL
/// </summary>
TPM_LAYOUTRTL = 0x8000,
/// <summary>
/// TPM_WORKAREA
/// </summary>
TPM_WORKAREA = 0x10000,
}
}

View File

@@ -102,7 +102,7 @@
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.135">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="WPF-UI.Violeta" Version="4.0.3">
<PackageReference Include="WPF-UI.Violeta" Version="4.0.3.2">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Lib.Harmony" Version="2.3.6">

View File

@@ -109,15 +109,20 @@
<InfoPanel_Files>{0} berkas</InfoPanel_Files>
<InfoPanel_FolderAndFile>({0} dan {1})</InfoPanel_FolderAndFile>
</id-ID>
<ko-KR>
<ko>
<UI_FontFamily>Segoe UI</UI_FontFamily>
<APP_START>QuickLook이 백그라운드에서 실행 중입니다.</APP_START>
<APP_SECOND>QuickLook이 이미 실행 중입니다</APP_SECOND>
<APP_SECOND_TEXT>QuickLook은 지원되는 파일 형식에 한해 파일 선택 후 스페이스바를 사용하여 미리보기를 할 수 있습니다.</APP_SECOND_TEXT>
<APP_SECOND_TEXT>QuickLook은 강조 표시된 상태에서 스페이스바를 눌러 특정 유형의 파일을 빠르게 미리 볼 수 있게 해줍니다.</APP_SECOND_TEXT>
<APP_PATH_NOT_WRITABLE>데이터 경로 "{0}"에 쓸 수 없습니다. 충분한 권한이 있는지 확인하세요.</APP_PATH_NOT_WRITABLE>
<MW_StayTop>맨 위에 유지</MW_StayTop>
<MW_BrowseFolder>{0} 열기</MW_BrowseFolder>
<MW_PreventClosing>닫힘 방지</MW_PreventClosing>
<MW_BrowseFolder>브라우저 {0}</MW_BrowseFolder>
<MW_Open>{0} 열기</MW_Open>
<MW_OpenWith>다음으로 열기 : {0}</MW_OpenWith>
<MW_OpenWith>{0}(으)로 열기</MW_OpenWith>
<MW_Run>{0} 실행</MW_Run>
<MW_Share>공유</MW_Share>
<Icon_RunAtStartup>시작 시 실행(&amp;S)</Icon_RunAtStartup>
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
<Icon_CheckUpdate>업데이트 확인(&amp;U)</Icon_CheckUpdate>
@@ -125,17 +130,18 @@
<Icon_OpenDataFolder>데이터 폴더 열기</Icon_OpenDataFolder>
<Icon_Restart>다시 시작(&amp;R)</Icon_Restart>
<Icon_Quit>종료(&amp;Q)</Icon_Quit>
<Update_NoUpdate>최신 버전을 사용 중입니다.</Update_NoUpdate>
<Update_Found>QuickLook {0} 버전이 출시되었습니다. 다운로드 페이지로 가려면 이곳을 클릭하십시오.</Update_Found>
<Update_Error>업데이트 확인 중 오류가 발생하였습니다: {0}</Update_Error>
<InfoPanel_LastModified>수정한 날짜: {0}</InfoPanel_LastModified>
<InfoPanel_DriveSize>용량: {0}, 사용 가능한 공간: {1}</InfoPanel_DriveSize>
<InfoPanel_Folder>폴더 {0}개</InfoPanel_Folder>
<InfoPanel_Folders>폴더 {0}개</InfoPanel_Folders>
<InfoPanel_File>파일 {0}개</InfoPanel_File>
<InfoPanel_Files>파일 {0}개</InfoPanel_Files>
<InfoPanel_FolderAndFile>({0}, {1})</InfoPanel_FolderAndFile>
</ko-KR>
<Update_NoUpdate>현재 최신 버전을 사용하고 있습니다.</Update_NoUpdate>
<Update_Found>QuickLook {0}이 출시되었습니다. 여기를 클릭하여 다운로드 페이지를 여세요.</Update_Found>
<Update_Error>업데이트 확인하는 중 오류가 발생습니다: {0}</Update_Error>
<InfoPanel_LastModified>{0}에 마지막으로 수정됨</InfoPanel_LastModified>
<InfoPanel_DriveSize>사용 가능한 용량 {0}, {1}</InfoPanel_DriveSize>
<InfoPanel_Folder>{0}개 폴더</InfoPanel_Folder>
<InfoPanel_Folders>{0}개 폴더</InfoPanel_Folders>
<InfoPanel_File>{0}개 파일</InfoPanel_File>
<InfoPanel_Files>{0}개 파일</InfoPanel_Files>
<InfoPanel_FolderAndFile>({0} {1})</InfoPanel_FolderAndFile>
<InfoPanel_CantPreventClosing>"닫힘 방지" 취소는 지원되지 않습니다</InfoPanel_CantPreventClosing>
</ko>
<ca>
<UI_FontFamily>Segoe UI</UI_FontFamily>
<APP_START>El QuickLook s'està executant en segon pla.</APP_START>

View File

@@ -15,79 +15,91 @@
// 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 QuickLook.Common.Commands;
using QuickLook.Common.Helpers;
using QuickLook.Helpers;
using QuickLook.Properties;
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using Wpf.Ui.Violeta.Win32;
using ToolTipIcon = Wpf.Ui.Violeta.Win32.ToolTipIcon;
namespace QuickLook;
internal class TrayIconManager : IDisposable
internal partial class TrayIconManager : IDisposable
{
private static TrayIconManager _instance;
private readonly NotifyIcon _icon;
private readonly TrayIconHost _icon;
private readonly MenuItem _itemAutorun =
new(TranslationHelper.Get("Icon_RunAtStartup"),
(sender, e) =>
private readonly TrayMenuItem _itemAutorun =
new()
{
Header = TranslationHelper.Get("Icon_RunAtStartup"),
Command = new RelayCommand(() =>
{
if (AutoStartupHelper.IsAutorun())
AutoStartupHelper.RemoveAutorunShortcut();
else
AutoStartupHelper.CreateAutorunShortcut();
})
{ Enabled = !App.IsUWP };
}),
IsEnabled = !App.IsUWP,
};
private TrayIconManager()
{
_icon = new NotifyIcon
_icon = new TrayIconHost
{
Text = string.Format(TranslationHelper.Get("Icon_ToolTip"),
ToolTipText = string.Format(TranslationHelper.Get("Icon_ToolTip"),
Application.ProductVersion),
Icon = GetTrayIconByDPI(),
ContextMenu = new ContextMenu(
Menu =
[
new MenuItem($"v{Application.ProductVersion}{(App.IsUWP ? " (UWP)" : string.Empty)}") {Enabled = false},
new MenuItem("-"),
new MenuItem(TranslationHelper.Get("Icon_CheckUpdate"), (_, _) => Updater.CheckForUpdates()),
new MenuItem(TranslationHelper.Get("Icon_GetPlugin"),
(_, _) => Process.Start("https://github.com/QL-Win/QuickLook/wiki/Available-Plugins")),
new MenuItem(TranslationHelper.Get("Icon_OpenDataFolder"), (_, _) => Process.Start("explorer.exe", SettingHelper.LocalDataPath)),
new TrayMenuItem()
{
Header = $"v{Application.ProductVersion}{(App.IsUWP ? " (UWP)" : string.Empty)}",
IsEnabled = false,
},
new TraySeparator(),
new TrayMenuItem()
{
Header = TranslationHelper.Get("Icon_CheckUpdate"),
Command = new RelayCommand(() => Updater.CheckForUpdates()),
},
new TrayMenuItem()
{
Header = TranslationHelper.Get("Icon_GetPlugin"),
Command = new RelayCommand(() => Process.Start("https://github.com/QL-Win/QuickLook/wiki/Available-Plugins")),
},
new TrayMenuItem()
{
Header = TranslationHelper.Get("Icon_OpenDataFolder"),
Command = new RelayCommand(() => Process.Start("explorer.exe", SettingHelper.LocalDataPath)),
},
_itemAutorun,
new MenuItem(TranslationHelper.Get("Icon_Restart"), (_, _) => Restart(forced: true)),
new MenuItem(TranslationHelper.Get("Icon_Quit"),
(_, _) => System.Windows.Application.Current.Shutdown())
]),
Visible = SettingHelper.Get("ShowTrayIcon", true)
new TrayMenuItem()
{
Header = TranslationHelper.Get("Icon_Restart"),
Command = new RelayCommand(() => Restart(forced: true)),
},
new TrayMenuItem()
{
Header = TranslationHelper.Get("Icon_Quit"),
Command = new RelayCommand(System.Windows.Application.Current.Shutdown),
}
],
IsVisible = SettingHelper.Get("ShowTrayIcon", true)
};
_icon.ContextMenu.Popup += (sender, e) => { _itemAutorun.Checked = AutoStartupHelper.IsAutorun(); };
// Readjust the display position of ContextMenu
if (SettingHelper.Get("ModernTrayIcon", true, "QuickLook"))
{
_icon.MouseDown += (_, e) =>
{
if (e.Button == MouseButtons.Right)
{
// Call ShowContextMenu here will be later than the native call,
// so here can readjust the ContextMenu position.
// You can check the source code to determine the behavior.
_icon.ShowContextMenu();
}
};
}
_icon.RightDown += (sender, e) => { _itemAutorun.IsChecked = AutoStartupHelper.IsAutorun(); };
}
public void Dispose()
{
_icon.Visible = false;
_icon.IsVisible = false;
}
public void Restart(string fileName = null, string dir = null, string args = null, int? exitCode = null, bool forced = false)
@@ -118,16 +130,16 @@ internal class TrayIconManager : IDisposable
Environment.Exit(exitCode ?? 'r' + 'e' + 's' + 't' + 'a' + 'r' + 't');
}
private Icon GetTrayIconByDPI()
private nint GetTrayIconByDPI()
{
var scale = DisplayDeviceHelper.GetCurrentScaleFactor().Vertical;
if (!App.IsWin10)
return scale > 1 ? Resources.app : Resources.app_16;
return scale > 1 ? Resources.app.Handle : Resources.app_16.Handle;
return OSThemeHelper.SystemUsesDarkTheme()
? (scale > 1 ? Resources.app_white : Resources.app_white_16)
: (scale > 1 ? Resources.app_black : Resources.app_black_16);
? (scale > 1 ? Resources.app_white.Handle : Resources.app_white_16.Handle)
: (scale > 1 ? Resources.app_black.Handle : Resources.app_black_16.Handle);
}
public static void ShowNotification(string title, string content, bool isError = false, int timeout = 5000,