dsh-windows-tray 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +146 -146
- package/bin/dsh-tray.js +100 -100
- package/build/build-tray-icons.ps1 +98 -98
- package/build/whale-render.html +8 -8
- package/docs/tray-dev-archive.md +57 -57
- package/install.ps1 +230 -184
- package/launcher/bh-menu.ps1 +56 -56
- package/launcher/dsh-actions.ps1 +50 -50
- package/launcher/dsh-all-menu.ps1 +106 -106
- package/launcher/dsh-control.ps1 +40 -40
- package/launcher/dsh-lib.ps1 +1 -1
- package/launcher/dsh-menu.ps1 +93 -93
- package/launcher/dsh-tray.bat +10 -10
- package/launcher/dsh-tray.ps1 +429 -418
- package/launcher/dsh-update.ps1 +115 -115
- package/package.json +36 -36
|
@@ -1,98 +1,98 @@
|
|
|
1
|
-
# build-tray-icons.ps1 —— 从官方鲸鱼 favicon.svg 生成系统托盘图标 (.ico)
|
|
2
|
-
# 用法: pwsh -NoProfile -File build-tray-icons.ps1 [-OutDir <dir>]
|
|
3
|
-
# 输入: whale-render.html 的截图 whale-512.png (浏览器渲染, 黑鲸/白底)
|
|
4
|
-
# 输出: dsh-tray-running.ico (品牌蓝 #4176e6) / dsh-tray-stopped.ico (灰 #81858c)
|
|
5
|
-
# 算法: 灰度 -> 透明度 (白=全透明, 黑=不透明), 整体填充目标色, 保留抗锯齿边缘
|
|
6
|
-
param(
|
|
7
|
-
[string]$OutDir = (Join-Path $PSScriptRoot 'icons')
|
|
8
|
-
)
|
|
9
|
-
$ErrorActionPreference = 'Stop'
|
|
10
|
-
Add-Type -AssemblyName System.Drawing
|
|
11
|
-
|
|
12
|
-
$srcPath = Join-Path $PSScriptRoot 'whale-512.png'
|
|
13
|
-
if (-not (Test-Path $srcPath)) { throw "missing $srcPath (先用浏览器打开 whale-render.html 并截图保存) " }
|
|
14
|
-
New-Item -ItemType Directory -Force -Path $OutDir | Out-Null
|
|
15
|
-
|
|
16
|
-
# 1) 裁出左上角 512x512
|
|
17
|
-
$raw = New-Object System.Drawing.Bitmap($srcPath)
|
|
18
|
-
$crop = New-Object System.Drawing.Bitmap 512, 512, ([System.Drawing.Imaging.PixelFormat]::Format32bppArgb)
|
|
19
|
-
$g = [System.Drawing.Graphics]::FromImage($crop)
|
|
20
|
-
$g.DrawImage($raw, (New-Object System.Drawing.Rectangle(0, 0, 512, 512)), (New-Object System.Drawing.Rectangle(0, 0, 512, 512)), [System.Drawing.GraphicsUnit]::Pixel)
|
|
21
|
-
$g.Dispose(); $raw.Dispose()
|
|
22
|
-
|
|
23
|
-
# 2) 灰度 -> 透明度 + 目标色填充 (LockBits 逐像素, 512x512 约 1~2 秒)
|
|
24
|
-
function Convert-GrayToTint([System.Drawing.Bitmap]$src, [int]$tr, [int]$tg, [int]$tb) {
|
|
25
|
-
$rect = New-Object System.Drawing.Rectangle(0, 0, $src.Width, $src.Height)
|
|
26
|
-
$data = $src.LockBits($rect, [System.Drawing.Imaging.ImageLockMode]::ReadOnly, [System.Drawing.Imaging.PixelFormat]::Format32bppArgb)
|
|
27
|
-
$bytes = New-Object byte[] ($data.Stride * $src.Height)
|
|
28
|
-
[System.Runtime.InteropServices.Marshal]::Copy($data.Scan0, $bytes, 0, $bytes.Length)
|
|
29
|
-
$src.UnlockBits($data)
|
|
30
|
-
$out = New-Object System.Drawing.Bitmap $src.Width, $src.Height, ([System.Drawing.Imaging.PixelFormat]::Format32bppArgb)
|
|
31
|
-
$outData = $out.LockBits($rect, [System.Drawing.Imaging.ImageLockMode]::WriteOnly, [System.Drawing.Imaging.PixelFormat]::Format32bppArgb)
|
|
32
|
-
$outBytes = New-Object byte[] ($outData.Stride * $out.Height)
|
|
33
|
-
for ($y = 0; $y -lt $src.Height; $y++) {
|
|
34
|
-
$row = $y * $data.Stride
|
|
35
|
-
$oRow = $y * $outData.Stride
|
|
36
|
-
for ($x = 0; $x -lt $src.Width; $x++) {
|
|
37
|
-
$i = $row + $x * 4
|
|
38
|
-
$lum = [int](($bytes[$i] + $bytes[$i + 1] + $bytes[$i + 2]) / 3)
|
|
39
|
-
$a = 255 - $lum
|
|
40
|
-
$j = $oRow + $x * 4
|
|
41
|
-
$outBytes[$j] = [byte]$tb
|
|
42
|
-
$outBytes[$j + 1] = [byte]$tg
|
|
43
|
-
$outBytes[$j + 2] = [byte]$tr
|
|
44
|
-
$outBytes[$j + 3] = [byte]$a
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
[System.Runtime.InteropServices.Marshal]::Copy($outBytes, 0, $outData.Scan0, $outBytes.Length)
|
|
48
|
-
$out.UnlockBits($outData)
|
|
49
|
-
return $out
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
# 3) 多尺寸 ICO (内嵌 PNG)
|
|
53
|
-
function Write-TrayIco([string]$path, [System.Drawing.Bitmap]$tint512, [int[]]$sizes) {
|
|
54
|
-
$blobs = @()
|
|
55
|
-
foreach ($s in $sizes) {
|
|
56
|
-
$bmp = New-Object System.Drawing.Bitmap $s, $s, ([System.Drawing.Imaging.PixelFormat]::Format32bppArgb)
|
|
57
|
-
$g = [System.Drawing.Graphics]::FromImage($bmp)
|
|
58
|
-
$g.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
|
|
59
|
-
$g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias
|
|
60
|
-
$g.DrawImage($tint512, 0, 0, $s, $s)
|
|
61
|
-
$g.Dispose()
|
|
62
|
-
$ms = New-Object System.IO.MemoryStream
|
|
63
|
-
$bmp.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png)
|
|
64
|
-
$blobs += , $ms.ToArray()
|
|
65
|
-
$ms.Dispose(); $bmp.Dispose()
|
|
66
|
-
}
|
|
67
|
-
$fs = [System.IO.File]::Create($path)
|
|
68
|
-
$bw = New-Object System.IO.BinaryWriter($fs)
|
|
69
|
-
$bw.Write([uint16]0); $bw.Write([uint16]1); $bw.Write([uint16]$sizes.Count)
|
|
70
|
-
$offset = 6 + 16 * $sizes.Count
|
|
71
|
-
for ($i = 0; $i -lt $sizes.Count; $i++) {
|
|
72
|
-
$s = $sizes[$i]
|
|
73
|
-
$dim = if ($s -ge 256) { 0 } else { $s }
|
|
74
|
-
$bw.Write([byte]$dim); $bw.Write([byte]$dim)
|
|
75
|
-
$bw.Write([byte]0); $bw.Write([byte]0)
|
|
76
|
-
$bw.Write([uint16]1); $bw.Write([uint16]32)
|
|
77
|
-
$bw.Write([uint32]$blobs[$i].Length); $bw.Write([uint32]$offset)
|
|
78
|
-
$offset += $blobs[$i].Length
|
|
79
|
-
}
|
|
80
|
-
foreach ($b in $blobs) { $bw.Write($b) }
|
|
81
|
-
$bw.Close(); $fs.Close()
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
# 品牌蓝 = DSH 主题 deepseek-500 #4176e6 ; 停止灰 = neutral-bluish-600 #81858c
|
|
85
|
-
$blue = Convert-GrayToTint $crop 0x41 0x76 0xE6
|
|
86
|
-
$gray = Convert-GrayToTint $crop 0x81 0x85 0x8C
|
|
87
|
-
$sizes = @(16, 24, 32, 48, 64, 256)
|
|
88
|
-
|
|
89
|
-
Write-TrayIco (Join-Path $OutDir 'dsh-tray-running.ico') $blue $sizes
|
|
90
|
-
Write-TrayIco (Join-Path $OutDir 'dsh-tray-stopped.ico') $gray $sizes
|
|
91
|
-
|
|
92
|
-
# 256px PNG 预览
|
|
93
|
-
$blue.Save((Join-Path $OutDir 'dsh-tray-running-preview.png'), [System.Drawing.Imaging.ImageFormat]::Png)
|
|
94
|
-
$gray.Save((Join-Path $OutDir 'dsh-tray-stopped-preview.png'), [System.Drawing.Imaging.ImageFormat]::Png)
|
|
95
|
-
|
|
96
|
-
$crop.Dispose(); $blue.Dispose(); $gray.Dispose()
|
|
97
|
-
Get-ChildItem $OutDir | Select-Object Name, Length | Format-Table -AutoSize
|
|
98
|
-
Write-Host "icons written to $OutDir"
|
|
1
|
+
# build-tray-icons.ps1 —— 从官方鲸鱼 favicon.svg 生成系统托盘图标 (.ico)
|
|
2
|
+
# 用法: pwsh -NoProfile -File build-tray-icons.ps1 [-OutDir <dir>]
|
|
3
|
+
# 输入: whale-render.html 的截图 whale-512.png (浏览器渲染, 黑鲸/白底)
|
|
4
|
+
# 输出: dsh-tray-running.ico (品牌蓝 #4176e6) / dsh-tray-stopped.ico (灰 #81858c)
|
|
5
|
+
# 算法: 灰度 -> 透明度 (白=全透明, 黑=不透明), 整体填充目标色, 保留抗锯齿边缘
|
|
6
|
+
param(
|
|
7
|
+
[string]$OutDir = (Join-Path $PSScriptRoot 'icons')
|
|
8
|
+
)
|
|
9
|
+
$ErrorActionPreference = 'Stop'
|
|
10
|
+
Add-Type -AssemblyName System.Drawing
|
|
11
|
+
|
|
12
|
+
$srcPath = Join-Path $PSScriptRoot 'whale-512.png'
|
|
13
|
+
if (-not (Test-Path $srcPath)) { throw "missing $srcPath (先用浏览器打开 whale-render.html 并截图保存) " }
|
|
14
|
+
New-Item -ItemType Directory -Force -Path $OutDir | Out-Null
|
|
15
|
+
|
|
16
|
+
# 1) 裁出左上角 512x512
|
|
17
|
+
$raw = New-Object System.Drawing.Bitmap($srcPath)
|
|
18
|
+
$crop = New-Object System.Drawing.Bitmap 512, 512, ([System.Drawing.Imaging.PixelFormat]::Format32bppArgb)
|
|
19
|
+
$g = [System.Drawing.Graphics]::FromImage($crop)
|
|
20
|
+
$g.DrawImage($raw, (New-Object System.Drawing.Rectangle(0, 0, 512, 512)), (New-Object System.Drawing.Rectangle(0, 0, 512, 512)), [System.Drawing.GraphicsUnit]::Pixel)
|
|
21
|
+
$g.Dispose(); $raw.Dispose()
|
|
22
|
+
|
|
23
|
+
# 2) 灰度 -> 透明度 + 目标色填充 (LockBits 逐像素, 512x512 约 1~2 秒)
|
|
24
|
+
function Convert-GrayToTint([System.Drawing.Bitmap]$src, [int]$tr, [int]$tg, [int]$tb) {
|
|
25
|
+
$rect = New-Object System.Drawing.Rectangle(0, 0, $src.Width, $src.Height)
|
|
26
|
+
$data = $src.LockBits($rect, [System.Drawing.Imaging.ImageLockMode]::ReadOnly, [System.Drawing.Imaging.PixelFormat]::Format32bppArgb)
|
|
27
|
+
$bytes = New-Object byte[] ($data.Stride * $src.Height)
|
|
28
|
+
[System.Runtime.InteropServices.Marshal]::Copy($data.Scan0, $bytes, 0, $bytes.Length)
|
|
29
|
+
$src.UnlockBits($data)
|
|
30
|
+
$out = New-Object System.Drawing.Bitmap $src.Width, $src.Height, ([System.Drawing.Imaging.PixelFormat]::Format32bppArgb)
|
|
31
|
+
$outData = $out.LockBits($rect, [System.Drawing.Imaging.ImageLockMode]::WriteOnly, [System.Drawing.Imaging.PixelFormat]::Format32bppArgb)
|
|
32
|
+
$outBytes = New-Object byte[] ($outData.Stride * $out.Height)
|
|
33
|
+
for ($y = 0; $y -lt $src.Height; $y++) {
|
|
34
|
+
$row = $y * $data.Stride
|
|
35
|
+
$oRow = $y * $outData.Stride
|
|
36
|
+
for ($x = 0; $x -lt $src.Width; $x++) {
|
|
37
|
+
$i = $row + $x * 4
|
|
38
|
+
$lum = [int](($bytes[$i] + $bytes[$i + 1] + $bytes[$i + 2]) / 3)
|
|
39
|
+
$a = 255 - $lum
|
|
40
|
+
$j = $oRow + $x * 4
|
|
41
|
+
$outBytes[$j] = [byte]$tb
|
|
42
|
+
$outBytes[$j + 1] = [byte]$tg
|
|
43
|
+
$outBytes[$j + 2] = [byte]$tr
|
|
44
|
+
$outBytes[$j + 3] = [byte]$a
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
[System.Runtime.InteropServices.Marshal]::Copy($outBytes, 0, $outData.Scan0, $outBytes.Length)
|
|
48
|
+
$out.UnlockBits($outData)
|
|
49
|
+
return $out
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# 3) 多尺寸 ICO (内嵌 PNG)
|
|
53
|
+
function Write-TrayIco([string]$path, [System.Drawing.Bitmap]$tint512, [int[]]$sizes) {
|
|
54
|
+
$blobs = @()
|
|
55
|
+
foreach ($s in $sizes) {
|
|
56
|
+
$bmp = New-Object System.Drawing.Bitmap $s, $s, ([System.Drawing.Imaging.PixelFormat]::Format32bppArgb)
|
|
57
|
+
$g = [System.Drawing.Graphics]::FromImage($bmp)
|
|
58
|
+
$g.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
|
|
59
|
+
$g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias
|
|
60
|
+
$g.DrawImage($tint512, 0, 0, $s, $s)
|
|
61
|
+
$g.Dispose()
|
|
62
|
+
$ms = New-Object System.IO.MemoryStream
|
|
63
|
+
$bmp.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png)
|
|
64
|
+
$blobs += , $ms.ToArray()
|
|
65
|
+
$ms.Dispose(); $bmp.Dispose()
|
|
66
|
+
}
|
|
67
|
+
$fs = [System.IO.File]::Create($path)
|
|
68
|
+
$bw = New-Object System.IO.BinaryWriter($fs)
|
|
69
|
+
$bw.Write([uint16]0); $bw.Write([uint16]1); $bw.Write([uint16]$sizes.Count)
|
|
70
|
+
$offset = 6 + 16 * $sizes.Count
|
|
71
|
+
for ($i = 0; $i -lt $sizes.Count; $i++) {
|
|
72
|
+
$s = $sizes[$i]
|
|
73
|
+
$dim = if ($s -ge 256) { 0 } else { $s }
|
|
74
|
+
$bw.Write([byte]$dim); $bw.Write([byte]$dim)
|
|
75
|
+
$bw.Write([byte]0); $bw.Write([byte]0)
|
|
76
|
+
$bw.Write([uint16]1); $bw.Write([uint16]32)
|
|
77
|
+
$bw.Write([uint32]$blobs[$i].Length); $bw.Write([uint32]$offset)
|
|
78
|
+
$offset += $blobs[$i].Length
|
|
79
|
+
}
|
|
80
|
+
foreach ($b in $blobs) { $bw.Write($b) }
|
|
81
|
+
$bw.Close(); $fs.Close()
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# 品牌蓝 = DSH 主题 deepseek-500 #4176e6 ; 停止灰 = neutral-bluish-600 #81858c
|
|
85
|
+
$blue = Convert-GrayToTint $crop 0x41 0x76 0xE6
|
|
86
|
+
$gray = Convert-GrayToTint $crop 0x81 0x85 0x8C
|
|
87
|
+
$sizes = @(16, 24, 32, 48, 64, 256)
|
|
88
|
+
|
|
89
|
+
Write-TrayIco (Join-Path $OutDir 'dsh-tray-running.ico') $blue $sizes
|
|
90
|
+
Write-TrayIco (Join-Path $OutDir 'dsh-tray-stopped.ico') $gray $sizes
|
|
91
|
+
|
|
92
|
+
# 256px PNG 预览
|
|
93
|
+
$blue.Save((Join-Path $OutDir 'dsh-tray-running-preview.png'), [System.Drawing.Imaging.ImageFormat]::Png)
|
|
94
|
+
$gray.Save((Join-Path $OutDir 'dsh-tray-stopped-preview.png'), [System.Drawing.Imaging.ImageFormat]::Png)
|
|
95
|
+
|
|
96
|
+
$crop.Dispose(); $blue.Dispose(); $gray.Dispose()
|
|
97
|
+
Get-ChildItem $OutDir | Select-Object Name, Length | Format-Table -AutoSize
|
|
98
|
+
Write-Host "icons written to $OutDir"
|
package/build/whale-render.html
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charset='utf-8'><style>html,body{margin:0;padding:0;background:#ffffff;overflow:hidden}</style></head><body><svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 50 50" fill="none">
|
|
2
|
-
<style>
|
|
3
|
-
@media (prefers-color-scheme: dark) {
|
|
4
|
-
path { fill: #fff; }
|
|
5
|
-
}
|
|
6
|
-
</style>
|
|
7
|
-
<path id="path" d="M48.8354 10.0479C48.3232 9.79199 48.1025 10.2798 47.8032 10.5278C47.7007 10.6079 47.6143 10.7119 47.5273 10.8076C46.7793 11.624 45.9048 12.1597 44.7622 12.0957C43.0923 12 41.666 12.5356 40.4058 13.8398C40.1377 12.2319 39.2476 11.272 37.8926 10.6558C37.1836 10.3359 36.4668 10.0156 35.9702 9.31982C35.6235 8.82373 35.5293 8.27197 35.356 7.72754C35.2456 7.3999 35.1353 7.06396 34.7651 7.00781C34.3633 6.94385 34.2056 7.2876 34.0479 7.57568C33.418 8.75195 33.1733 10.0479 33.1973 11.3599C33.2524 14.312 34.4736 16.6641 36.8999 18.3359C37.1758 18.5278 37.2466 18.7197 37.1597 19C36.9946 19.5757 36.7974 20.1357 36.624 20.7119C36.5137 21.0801 36.3486 21.1597 35.9624 21C34.6309 20.4321 33.481 19.5918 32.4644 18.5757C30.7393 16.8721 29.1792 14.9917 27.2334 13.52C26.7764 13.1758 26.3193 12.856 25.8467 12.5518C23.8618 10.584 26.1069 8.96777 26.627 8.77588C27.1704 8.57568 26.8159 7.8877 25.0591 7.896C23.3022 7.90381 21.6953 8.50391 19.647 9.30371C19.3477 9.42383 19.0322 9.51172 18.7095 9.58398C16.8501 9.22363 14.9199 9.14355 12.9033 9.37598C9.10596 9.80762 6.07275 11.6396 3.84326 14.7681C1.16455 18.5278 0.53418 22.7998 1.30664 27.2559C2.11768 31.9521 4.46582 35.8398 8.07373 38.8799C11.8159 42.0322 16.1255 43.5762 21.041 43.2803C24.0269 43.104 27.3516 42.6963 31.1016 39.4561C32.0469 39.936 33.0396 40.1279 34.686 40.272C35.9546 40.3921 37.1758 40.208 38.1211 40.0078C39.6021 39.688 39.4995 38.2881 38.9639 38.0322C34.623 35.9678 35.5762 36.8081 34.71 36.1279C36.9155 33.4639 40.2402 30.6958 41.54 21.728C41.6426 21.0161 41.5557 20.5679 41.54 19.9917C41.5322 19.6396 41.6108 19.5039 42.0049 19.4639C43.0923 19.3359 44.1479 19.0317 45.1167 18.4878C47.9292 16.9199 49.064 14.3438 49.3315 11.2559C49.3711 10.7837 49.3237 10.2959 48.8354 10.0479ZM24.3262 37.8398C20.1196 34.4639 18.0791 33.3521 17.2358 33.3999C16.4482 33.4482 16.5898 34.3682 16.7632 34.9678C16.9443 35.5601 17.1812 35.9683 17.5117 36.4878C17.7402 36.832 17.8979 37.3442 17.2832 37.728C15.9282 38.584 13.5728 37.4399 13.4624 37.3838C10.7207 35.7358 8.42822 33.5601 6.81348 30.584C5.25342 27.7197 4.34766 24.6479 4.19775 21.3677C4.1582 20.5757 4.38672 20.2959 5.15869 20.1519C6.17529 19.96 7.22314 19.9199 8.23926 20.0718C12.5327 20.7119 16.1885 22.6719 19.2529 25.7759C21.002 27.5439 22.3252 29.6558 23.6885 31.7202C25.1377 33.9121 26.6978 36 28.6831 37.7119C29.3843 38.312 29.9434 38.7681 30.479 39.104C28.8643 39.2881 26.1699 39.3281 24.3262 37.8398ZM26.3433 24.6001C26.3433 24.248 26.6191 23.9678 26.9658 23.9678C27.0444 23.9678 27.1152 23.9839 27.1782 24.0078C27.2651 24.04 27.3438 24.0879 27.4067 24.1602C27.5171 24.272 27.5801 24.4321 27.5801 24.6001C27.5801 24.9521 27.3042 25.2319 26.9575 25.2319C26.6108 25.2319 26.3433 24.9521 26.3433 24.6001ZM32.6064 27.8799C32.2046 28.0479 31.8027 28.1919 31.4165 28.208C30.8179 28.2397 30.1641 27.9922 29.8096 27.688C29.2583 27.2158 28.8643 26.9521 28.6987 26.1279C28.6279 25.7759 28.6675 25.2319 28.7305 24.9199C28.8721 24.248 28.7144 23.8159 28.2495 23.4238C27.8716 23.104 27.3911 23.0161 26.8633 23.0161C26.666 23.0161 26.4849 22.9277 26.3511 22.856C26.1304 22.7441 25.9492 22.4639 26.1226 22.1201C26.1777 22.0078 26.4458 21.7358 26.5088 21.688C27.2256 21.272 28.0527 21.4077 28.8169 21.7197C29.5259 22.0161 30.0615 22.5601 30.834 23.3281C31.6216 24.2559 31.7632 24.5117 32.2124 25.208C32.5669 25.752 32.8901 26.312 33.1104 26.9521C33.2446 27.3521 33.0713 27.6802 32.6064 27.8799Z" fill="#000" fill-opacity="1.000000" fill-rule="nonzero"/>
|
|
8
|
-
</svg>
|
|
1
|
+
<!DOCTYPE html><html><head><meta charset='utf-8'><style>html,body{margin:0;padding:0;background:#ffffff;overflow:hidden}</style></head><body><svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 50 50" fill="none">
|
|
2
|
+
<style>
|
|
3
|
+
@media (prefers-color-scheme: dark) {
|
|
4
|
+
path { fill: #fff; }
|
|
5
|
+
}
|
|
6
|
+
</style>
|
|
7
|
+
<path id="path" d="M48.8354 10.0479C48.3232 9.79199 48.1025 10.2798 47.8032 10.5278C47.7007 10.6079 47.6143 10.7119 47.5273 10.8076C46.7793 11.624 45.9048 12.1597 44.7622 12.0957C43.0923 12 41.666 12.5356 40.4058 13.8398C40.1377 12.2319 39.2476 11.272 37.8926 10.6558C37.1836 10.3359 36.4668 10.0156 35.9702 9.31982C35.6235 8.82373 35.5293 8.27197 35.356 7.72754C35.2456 7.3999 35.1353 7.06396 34.7651 7.00781C34.3633 6.94385 34.2056 7.2876 34.0479 7.57568C33.418 8.75195 33.1733 10.0479 33.1973 11.3599C33.2524 14.312 34.4736 16.6641 36.8999 18.3359C37.1758 18.5278 37.2466 18.7197 37.1597 19C36.9946 19.5757 36.7974 20.1357 36.624 20.7119C36.5137 21.0801 36.3486 21.1597 35.9624 21C34.6309 20.4321 33.481 19.5918 32.4644 18.5757C30.7393 16.8721 29.1792 14.9917 27.2334 13.52C26.7764 13.1758 26.3193 12.856 25.8467 12.5518C23.8618 10.584 26.1069 8.96777 26.627 8.77588C27.1704 8.57568 26.8159 7.8877 25.0591 7.896C23.3022 7.90381 21.6953 8.50391 19.647 9.30371C19.3477 9.42383 19.0322 9.51172 18.7095 9.58398C16.8501 9.22363 14.9199 9.14355 12.9033 9.37598C9.10596 9.80762 6.07275 11.6396 3.84326 14.7681C1.16455 18.5278 0.53418 22.7998 1.30664 27.2559C2.11768 31.9521 4.46582 35.8398 8.07373 38.8799C11.8159 42.0322 16.1255 43.5762 21.041 43.2803C24.0269 43.104 27.3516 42.6963 31.1016 39.4561C32.0469 39.936 33.0396 40.1279 34.686 40.272C35.9546 40.3921 37.1758 40.208 38.1211 40.0078C39.6021 39.688 39.4995 38.2881 38.9639 38.0322C34.623 35.9678 35.5762 36.8081 34.71 36.1279C36.9155 33.4639 40.2402 30.6958 41.54 21.728C41.6426 21.0161 41.5557 20.5679 41.54 19.9917C41.5322 19.6396 41.6108 19.5039 42.0049 19.4639C43.0923 19.3359 44.1479 19.0317 45.1167 18.4878C47.9292 16.9199 49.064 14.3438 49.3315 11.2559C49.3711 10.7837 49.3237 10.2959 48.8354 10.0479ZM24.3262 37.8398C20.1196 34.4639 18.0791 33.3521 17.2358 33.3999C16.4482 33.4482 16.5898 34.3682 16.7632 34.9678C16.9443 35.5601 17.1812 35.9683 17.5117 36.4878C17.7402 36.832 17.8979 37.3442 17.2832 37.728C15.9282 38.584 13.5728 37.4399 13.4624 37.3838C10.7207 35.7358 8.42822 33.5601 6.81348 30.584C5.25342 27.7197 4.34766 24.6479 4.19775 21.3677C4.1582 20.5757 4.38672 20.2959 5.15869 20.1519C6.17529 19.96 7.22314 19.9199 8.23926 20.0718C12.5327 20.7119 16.1885 22.6719 19.2529 25.7759C21.002 27.5439 22.3252 29.6558 23.6885 31.7202C25.1377 33.9121 26.6978 36 28.6831 37.7119C29.3843 38.312 29.9434 38.7681 30.479 39.104C28.8643 39.2881 26.1699 39.3281 24.3262 37.8398ZM26.3433 24.6001C26.3433 24.248 26.6191 23.9678 26.9658 23.9678C27.0444 23.9678 27.1152 23.9839 27.1782 24.0078C27.2651 24.04 27.3438 24.0879 27.4067 24.1602C27.5171 24.272 27.5801 24.4321 27.5801 24.6001C27.5801 24.9521 27.3042 25.2319 26.9575 25.2319C26.6108 25.2319 26.3433 24.9521 26.3433 24.6001ZM32.6064 27.8799C32.2046 28.0479 31.8027 28.1919 31.4165 28.208C30.8179 28.2397 30.1641 27.9922 29.8096 27.688C29.2583 27.2158 28.8643 26.9521 28.6987 26.1279C28.6279 25.7759 28.6675 25.2319 28.7305 24.9199C28.8721 24.248 28.7144 23.8159 28.2495 23.4238C27.8716 23.104 27.3911 23.0161 26.8633 23.0161C26.666 23.0161 26.4849 22.9277 26.3511 22.856C26.1304 22.7441 25.9492 22.4639 26.1226 22.1201C26.1777 22.0078 26.4458 21.7358 26.5088 21.688C27.2256 21.272 28.0527 21.4077 28.8169 21.7197C29.5259 22.0161 30.0615 22.5601 30.834 23.3281C31.6216 24.2559 31.7632 24.5117 32.2124 25.208C32.5669 25.752 32.8901 26.312 33.1104 26.9521C33.2446 27.3521 33.0713 27.6802 32.6064 27.8799Z" fill="#000" fill-opacity="1.000000" fill-rule="nonzero"/>
|
|
8
|
+
</svg>
|
|
9
9
|
</body></html>
|
package/docs/tray-dev-archive.md
CHANGED
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
# 系统托盘开发归档(v1.0.0 · 2026-08-27)
|
|
2
|
-
|
|
3
|
-
> 托盘已发布为 npm 包 **`dsh-windows-tray`**,日常安装 / 使用 / 更新 / 卸载见 [system-tray-guide.md](system-tray-guide.md)。
|
|
4
|
-
> 本文仅归档开发期的**架构决策与历史记录**(源码细节、文件清单不再维护);通用踩坑已归入 [powershell-pitfalls.md](powershell-pitfalls.md)。
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## 1. 架构决策(仍生效)
|
|
9
|
-
|
|
10
|
-
| 决策 | 理由 |
|
|
11
|
-
| :--- | :--- |
|
|
12
|
-
| **独立常驻进程**(不嵌入 dsh) | 需求是"看到未启动状态"——进程内嵌图标会随 dsh 消失;旁观者进程才能表达 运行/停止 两态,且能重启已死的 dsh |
|
|
13
|
-
| **端口探测**(每 2s TCP 连 127.0.0.1:3088,500ms 超时) | 不持有进程句柄;dsh 重启 PID 变化也不误判;对 dsh 实现零依赖 |
|
|
14
|
-
| **动作独立进程**(隐藏执行) | 菜单动作(含 taskkill、等待轮询)不阻塞托盘 UI 线程 |
|
|
15
|
-
| **静态 .ico 图标资源** | 不依赖 dsh 运行时接口;缺失时 `New-FallbackIcon` 画纯色圆点兜底 |
|
|
16
|
-
| **命名互斥锁单实例** | 替代 WMI 扫描,无竞态;被强杀遗留的锁自动接管(AbandonedMutexException) |
|
|
17
|
-
| **TUI 单实例锁**(仅启动侧) | 防连点误开多窗口;检测/停止侧本就支持多实例(全查全杀);物理上 TUI 可多开,放开只需移除启动锁 |
|
|
18
|
-
|
|
19
|
-
进程模型:
|
|
20
|
-
|
|
21
|
-
```
|
|
22
|
-
托盘(pwsh) ──2s 轮询──► 端口 3088 (dsh web)
|
|
23
|
-
│ └──────────────► node 进程命令行含 'dsh-tui' (TUI)
|
|
24
|
-
├── 菜单动作 ──► 独立隐藏进程 (带日志)
|
|
25
|
-
└── 自更新 ──► npm install -g → 重部署 → 重启托盘
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## 2. 图标渲染管线(摘要)
|
|
29
|
-
|
|
30
|
-
官方 `favicon.svg`(鲸鱼)→ 浏览器渲染 512px → PowerShell 逐像素"亮度转透明度 + 填充目标色" → 多尺寸 ICO(16/24/32/48/64/256)。运行态品牌蓝 `#4176E6`,停止态中性灰 `#81858C`。源图与脚本已内置 npm 包 `build/`,`dsh-tray icons` 可随时再生成。
|
|
31
|
-
|
|
32
|
-
## 3. 社区借鉴(发布前调研)
|
|
33
|
-
|
|
34
|
-
npm 上两个同思路项目(`dsh-tray`、`dsh-tray-launcher`,均一周内发布),落地到本项目:
|
|
35
|
-
|
|
36
|
-
- **命名互斥锁单实例**(替代 WMI 扫描,无竞态)
|
|
37
|
-
- **浅色圆角菜单**(白底 + 圆角 hover + 细分隔线 + P/Invoke 圆角窗口 + CS_DROPSHADOW 投影,主/子菜单通用)
|
|
38
|
-
- **菜单打开时强制刷新** TUI 状态(`add_Opening`),平时 TUI 检测 20s 节流
|
|
39
|
-
- **停止 DSH 前 MessageBox 确认**、**版本烙印**(启动日志显示 v1.0.0,npm 安装版优先读 package.json)
|
|
40
|
-
|
|
41
|
-
不照搬的差异化设计:**旁观者架构**(退出托盘不影响 dsh)、**2s 端口轮询状态图标**、**TUI 启停集成 / 官方鲸鱼图标 / 控制台共享公共库**。
|
|
42
|
-
|
|
43
|
-
## 4. 需求变更决策记录
|
|
44
|
-
|
|
45
|
-
| 时间 | 需求 | 决策 |
|
|
46
|
-
| :--- | :--- | :--- |
|
|
47
|
-
| 2026-08-27 | 托盘内 npm 自更新 | 曾按"更新应由 npm 标准流程承担"移除 → 用户决定恢复("更新加回去吧")→ 菜单「版本信息 ▸」(位于退出托盘上方,非日常功能区)提供 检查更新 / 一键更新;README 同时保留 npm CLI 路径 |
|
|
48
|
-
| 2026-08-27 | 菜单太长 | DSH / TUI 收进子菜单(借鉴更新子菜单收纳思路) |
|
|
49
|
-
| 2026-08-27 | 只显示 dsh 状态 | 顶部双状态行:`DSH 状态: …` / `TUI 状态: …`(独立检测、互不干扰) |
|
|
50
|
-
| 2026-08-27 | 一级/二级菜单间隔大 | 根因:箭头预留撑宽父项 + 事件闭包 $null(详见 powershell-pitfalls §1.1 / §4.2) |
|
|
51
|
-
|
|
52
|
-
## 5. 已知边界
|
|
53
|
-
|
|
54
|
-
1. 3088 被其他程序占用时托盘误判"运行中"(属端口问题,与托盘无关)
|
|
55
|
-
2. 二态检测:只区分 运行/停止,无法区分"忙/卡死"(可扩展 HTTP 探测做三态)
|
|
56
|
-
3. TUI 单实例是策略而非物理限制(见 §1 决策表)
|
|
57
|
-
4. 单实例互斥锁在极端竞态下仍有极小双启动概率(影响可忽略)
|
|
1
|
+
# 系统托盘开发归档(v1.0.0 · 2026-08-27)
|
|
2
|
+
|
|
3
|
+
> 托盘已发布为 npm 包 **`dsh-windows-tray`**,日常安装 / 使用 / 更新 / 卸载见 [system-tray-guide.md](system-tray-guide.md)。
|
|
4
|
+
> 本文仅归档开发期的**架构决策与历史记录**(源码细节、文件清单不再维护);通用踩坑已归入 [powershell-pitfalls.md](powershell-pitfalls.md)。
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 1. 架构决策(仍生效)
|
|
9
|
+
|
|
10
|
+
| 决策 | 理由 |
|
|
11
|
+
| :--- | :--- |
|
|
12
|
+
| **独立常驻进程**(不嵌入 dsh) | 需求是"看到未启动状态"——进程内嵌图标会随 dsh 消失;旁观者进程才能表达 运行/停止 两态,且能重启已死的 dsh |
|
|
13
|
+
| **端口探测**(每 2s TCP 连 127.0.0.1:3088,500ms 超时) | 不持有进程句柄;dsh 重启 PID 变化也不误判;对 dsh 实现零依赖 |
|
|
14
|
+
| **动作独立进程**(隐藏执行) | 菜单动作(含 taskkill、等待轮询)不阻塞托盘 UI 线程 |
|
|
15
|
+
| **静态 .ico 图标资源** | 不依赖 dsh 运行时接口;缺失时 `New-FallbackIcon` 画纯色圆点兜底 |
|
|
16
|
+
| **命名互斥锁单实例** | 替代 WMI 扫描,无竞态;被强杀遗留的锁自动接管(AbandonedMutexException) |
|
|
17
|
+
| **TUI 单实例锁**(仅启动侧) | 防连点误开多窗口;检测/停止侧本就支持多实例(全查全杀);物理上 TUI 可多开,放开只需移除启动锁 |
|
|
18
|
+
|
|
19
|
+
进程模型:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
托盘(pwsh) ──2s 轮询──► 端口 3088 (dsh web)
|
|
23
|
+
│ └──────────────► node 进程命令行含 'dsh-tui' (TUI)
|
|
24
|
+
├── 菜单动作 ──► 独立隐藏进程 (带日志)
|
|
25
|
+
└── 自更新 ──► npm install -g → 重部署 → 重启托盘
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 2. 图标渲染管线(摘要)
|
|
29
|
+
|
|
30
|
+
官方 `favicon.svg`(鲸鱼)→ 浏览器渲染 512px → PowerShell 逐像素"亮度转透明度 + 填充目标色" → 多尺寸 ICO(16/24/32/48/64/256)。运行态品牌蓝 `#4176E6`,停止态中性灰 `#81858C`。源图与脚本已内置 npm 包 `build/`,`dsh-tray icons` 可随时再生成。
|
|
31
|
+
|
|
32
|
+
## 3. 社区借鉴(发布前调研)
|
|
33
|
+
|
|
34
|
+
npm 上两个同思路项目(`dsh-tray`、`dsh-tray-launcher`,均一周内发布),落地到本项目:
|
|
35
|
+
|
|
36
|
+
- **命名互斥锁单实例**(替代 WMI 扫描,无竞态)
|
|
37
|
+
- **浅色圆角菜单**(白底 + 圆角 hover + 细分隔线 + P/Invoke 圆角窗口 + CS_DROPSHADOW 投影,主/子菜单通用)
|
|
38
|
+
- **菜单打开时强制刷新** TUI 状态(`add_Opening`),平时 TUI 检测 20s 节流
|
|
39
|
+
- **停止 DSH 前 MessageBox 确认**、**版本烙印**(启动日志显示 v1.0.0,npm 安装版优先读 package.json)
|
|
40
|
+
|
|
41
|
+
不照搬的差异化设计:**旁观者架构**(退出托盘不影响 dsh)、**2s 端口轮询状态图标**、**TUI 启停集成 / 官方鲸鱼图标 / 控制台共享公共库**。
|
|
42
|
+
|
|
43
|
+
## 4. 需求变更决策记录
|
|
44
|
+
|
|
45
|
+
| 时间 | 需求 | 决策 |
|
|
46
|
+
| :--- | :--- | :--- |
|
|
47
|
+
| 2026-08-27 | 托盘内 npm 自更新 | 曾按"更新应由 npm 标准流程承担"移除 → 用户决定恢复("更新加回去吧")→ 菜单「版本信息 ▸」(位于退出托盘上方,非日常功能区)提供 检查更新 / 一键更新;README 同时保留 npm CLI 路径 |
|
|
48
|
+
| 2026-08-27 | 菜单太长 | DSH / TUI 收进子菜单(借鉴更新子菜单收纳思路) |
|
|
49
|
+
| 2026-08-27 | 只显示 dsh 状态 | 顶部双状态行:`DSH 状态: …` / `TUI 状态: …`(独立检测、互不干扰) |
|
|
50
|
+
| 2026-08-27 | 一级/二级菜单间隔大 | 根因:箭头预留撑宽父项 + 事件闭包 $null(详见 powershell-pitfalls §1.1 / §4.2) |
|
|
51
|
+
|
|
52
|
+
## 5. 已知边界
|
|
53
|
+
|
|
54
|
+
1. 3088 被其他程序占用时托盘误判"运行中"(属端口问题,与托盘无关)
|
|
55
|
+
2. 二态检测:只区分 运行/停止,无法区分"忙/卡死"(可扩展 HTTP 探测做三态)
|
|
56
|
+
3. TUI 单实例是策略而非物理限制(见 §1 决策表)
|
|
57
|
+
4. 单实例互斥锁在极端竞态下仍有极小双启动概率(影响可忽略)
|