pake-cli 3.9.1 โ 3.10.0
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/dist/cli.js +121 -5
- package/package.json +3 -3
- package/src-tauri/Cargo.lock +53 -53
- package/src-tauri/Cargo.toml +1 -1
- package/src-tauri/assets/macos/dmg/background.png +0 -0
- package/src-tauri/pake.json +3 -1
- package/src-tauri/src/app/config.rs +7 -3
- package/src-tauri/src/app/menu.rs +17 -3
- package/src-tauri/src/app/setup.rs +15 -3
- package/src-tauri/src/app/window.rs +64 -6
- package/src-tauri/src/inject/event.js +30 -5
- package/src-tauri/src/lib.rs +22 -11
- package/src-tauri/tauri.conf.json +1 -1
- package/src-tauri/.pake/pake.json +0 -43
- package/src-tauri/.pake/tauri.conf.json +0 -44
- package/src-tauri/.pake/tauri.linux.conf.json +0 -12
- package/src-tauri/.pake/tauri.macos.conf.json +0 -30
- package/src-tauri/.pake/tauri.windows.conf.json +0 -15
package/dist/cli.js
CHANGED
|
@@ -22,7 +22,7 @@ import * as psl from 'psl';
|
|
|
22
22
|
import { InvalidArgumentError, program as program$1, Option } from 'commander';
|
|
23
23
|
|
|
24
24
|
var name = "pake-cli";
|
|
25
|
-
var version = "3.
|
|
25
|
+
var version = "3.10.0";
|
|
26
26
|
var description = "๐คฑ๐ป Turn any webpage into a desktop app with one command. ๐คฑ๐ป ไธ้ฎๆๅ
็ฝ้กต็ๆ่ฝป้ๆก้ขๅบ็จใ";
|
|
27
27
|
var engines = {
|
|
28
28
|
node: ">=18.0.0"
|
|
@@ -94,7 +94,7 @@ var devDependencies = {
|
|
|
94
94
|
"@rollup/plugin-replace": "^6.0.3",
|
|
95
95
|
"@rollup/plugin-terser": "^0.4.4",
|
|
96
96
|
"@types/fs-extra": "^11.0.4",
|
|
97
|
-
"@types/node": "^25.3.
|
|
97
|
+
"@types/node": "^25.3.2",
|
|
98
98
|
"@types/page-icon": "^0.3.6",
|
|
99
99
|
"@types/prompts": "^2.4.9",
|
|
100
100
|
"@types/tmp": "^0.2.6",
|
|
@@ -102,7 +102,7 @@ var devDependencies = {
|
|
|
102
102
|
"app-root-path": "^3.1.0",
|
|
103
103
|
"cross-env": "^10.1.0",
|
|
104
104
|
prettier: "^3.8.1",
|
|
105
|
-
rollup: "^4.
|
|
105
|
+
rollup: "^4.59.0",
|
|
106
106
|
"rollup-plugin-typescript2": "^0.36.0",
|
|
107
107
|
tslib: "^2.8.1",
|
|
108
108
|
typescript: "^5.9.3",
|
|
@@ -484,7 +484,7 @@ async function mergeConfig(url, options, tauriConf) {
|
|
|
484
484
|
await fsExtra.copy(sourcePath, destPath);
|
|
485
485
|
}
|
|
486
486
|
}));
|
|
487
|
-
const { width, height, fullscreen, maximize, hideTitleBar, alwaysOnTop, appVersion, darkMode, disabledWebShortcuts, activationShortcut, userAgent, showSystemTray, systemTrayIcon, useLocalFile, identifier, name = 'pake-app', resizable = true, inject, proxyUrl, installerLanguage, hideOnClose, incognito, title, wasm, enableDragDrop, multiInstance, startToTray, forceInternalNavigation, zoom, minWidth, minHeight, ignoreCertificateErrors, newWindow, } = options;
|
|
487
|
+
const { width, height, fullscreen, maximize, hideTitleBar, alwaysOnTop, appVersion, darkMode, disabledWebShortcuts, activationShortcut, userAgent, showSystemTray, systemTrayIcon, useLocalFile, identifier, name = 'pake-app', resizable = true, inject, proxyUrl, installerLanguage, hideOnClose, incognito, title, wasm, enableDragDrop, multiInstance, multiWindow, startToTray, forceInternalNavigation, internalUrlRegex, zoom, minWidth, minHeight, ignoreCertificateErrors, newWindow, } = options;
|
|
488
488
|
const { platform } = process;
|
|
489
489
|
const platformHideOnClose = hideOnClose ?? platform === 'darwin';
|
|
490
490
|
const tauriConfWindowOptions = {
|
|
@@ -505,6 +505,7 @@ async function mergeConfig(url, options, tauriConf) {
|
|
|
505
505
|
enable_drag_drop: enableDragDrop,
|
|
506
506
|
start_to_tray: startToTray && showSystemTray,
|
|
507
507
|
force_internal_navigation: forceInternalNavigation,
|
|
508
|
+
internal_url_regex: internalUrlRegex,
|
|
508
509
|
zoom,
|
|
509
510
|
min_width: minWidth,
|
|
510
511
|
min_height: minHeight,
|
|
@@ -728,6 +729,7 @@ Terminal=false
|
|
|
728
729
|
}
|
|
729
730
|
tauriConf.pake.proxy_url = proxyUrl || '';
|
|
730
731
|
tauriConf.pake.multi_instance = multiInstance;
|
|
732
|
+
tauriConf.pake.multi_window = multiWindow;
|
|
731
733
|
// Configure WASM support with required HTTP headers
|
|
732
734
|
if (wasm) {
|
|
733
735
|
tauriConf.app.security = {
|
|
@@ -1397,6 +1399,108 @@ class BuilderProvider {
|
|
|
1397
1399
|
}
|
|
1398
1400
|
}
|
|
1399
1401
|
|
|
1402
|
+
const ICO_HEADER_SIZE = 6;
|
|
1403
|
+
const ICO_DIR_ENTRY_SIZE = 16;
|
|
1404
|
+
const ICO_TYPE_ICON = 1;
|
|
1405
|
+
function decodeDimension(value) {
|
|
1406
|
+
return value === 0 ? 256 : value;
|
|
1407
|
+
}
|
|
1408
|
+
function compareByPreferredSize(preferredSize) {
|
|
1409
|
+
return (a, b) => {
|
|
1410
|
+
const aSize = Math.max(a.width, a.height);
|
|
1411
|
+
const bSize = Math.max(b.width, b.height);
|
|
1412
|
+
const aExact = aSize === preferredSize ? 0 : 1;
|
|
1413
|
+
const bExact = bSize === preferredSize ? 0 : 1;
|
|
1414
|
+
if (aExact !== bExact)
|
|
1415
|
+
return aExact - bExact;
|
|
1416
|
+
const aDistance = Math.abs(aSize - preferredSize);
|
|
1417
|
+
const bDistance = Math.abs(bSize - preferredSize);
|
|
1418
|
+
if (aDistance !== bDistance)
|
|
1419
|
+
return aDistance - bDistance;
|
|
1420
|
+
const aSmaller = aSize < preferredSize ? 1 : 0;
|
|
1421
|
+
const bSmaller = bSize < preferredSize ? 1 : 0;
|
|
1422
|
+
if (aSmaller !== bSmaller)
|
|
1423
|
+
return aSmaller - bSmaller;
|
|
1424
|
+
if (a.bitCount !== b.bitCount)
|
|
1425
|
+
return b.bitCount - a.bitCount;
|
|
1426
|
+
if (aSize !== bSize)
|
|
1427
|
+
return bSize - aSize;
|
|
1428
|
+
return a.index - b.index;
|
|
1429
|
+
};
|
|
1430
|
+
}
|
|
1431
|
+
function parseIcoBuffer(buffer) {
|
|
1432
|
+
if (buffer.length < ICO_HEADER_SIZE) {
|
|
1433
|
+
throw new Error('Invalid ICO: header too short.');
|
|
1434
|
+
}
|
|
1435
|
+
const reserved = buffer.readUInt16LE(0);
|
|
1436
|
+
const type = buffer.readUInt16LE(2);
|
|
1437
|
+
const count = buffer.readUInt16LE(4);
|
|
1438
|
+
if (reserved !== 0 || type !== ICO_TYPE_ICON || count < 1) {
|
|
1439
|
+
throw new Error('Invalid ICO: invalid header.');
|
|
1440
|
+
}
|
|
1441
|
+
const tableSize = ICO_HEADER_SIZE + count * ICO_DIR_ENTRY_SIZE;
|
|
1442
|
+
if (buffer.length < tableSize) {
|
|
1443
|
+
throw new Error('Invalid ICO: directory table too short.');
|
|
1444
|
+
}
|
|
1445
|
+
const entries = [];
|
|
1446
|
+
for (let i = 0; i < count; i++) {
|
|
1447
|
+
const offset = ICO_HEADER_SIZE + i * ICO_DIR_ENTRY_SIZE;
|
|
1448
|
+
const widthByte = buffer.readUInt8(offset);
|
|
1449
|
+
const heightByte = buffer.readUInt8(offset + 1);
|
|
1450
|
+
const bitCount = buffer.readUInt16LE(offset + 6);
|
|
1451
|
+
const bytesInRes = buffer.readUInt32LE(offset + 8);
|
|
1452
|
+
const imageOffset = buffer.readUInt32LE(offset + 12);
|
|
1453
|
+
if (bytesInRes < 1 || imageOffset + bytesInRes > buffer.length) {
|
|
1454
|
+
throw new Error('Invalid ICO: frame out of bounds.');
|
|
1455
|
+
}
|
|
1456
|
+
entries.push({
|
|
1457
|
+
index: i,
|
|
1458
|
+
width: decodeDimension(widthByte),
|
|
1459
|
+
height: decodeDimension(heightByte),
|
|
1460
|
+
bitCount,
|
|
1461
|
+
bytesInRes,
|
|
1462
|
+
imageOffset,
|
|
1463
|
+
directory: buffer.subarray(offset, offset + ICO_DIR_ENTRY_SIZE),
|
|
1464
|
+
data: buffer.subarray(imageOffset, imageOffset + bytesInRes),
|
|
1465
|
+
});
|
|
1466
|
+
}
|
|
1467
|
+
return entries;
|
|
1468
|
+
}
|
|
1469
|
+
function buildReorderedIcoBuffer(buffer, preferredSize) {
|
|
1470
|
+
const entries = parseIcoBuffer(buffer);
|
|
1471
|
+
const ordered = [...entries].sort(compareByPreferredSize(preferredSize));
|
|
1472
|
+
const count = ordered.length;
|
|
1473
|
+
const tableSize = ICO_HEADER_SIZE + count * ICO_DIR_ENTRY_SIZE;
|
|
1474
|
+
const payloadSize = ordered.reduce((acc, entry) => acc + entry.data.length, 0);
|
|
1475
|
+
const output = Buffer.alloc(tableSize + payloadSize);
|
|
1476
|
+
output.writeUInt16LE(0, 0);
|
|
1477
|
+
output.writeUInt16LE(ICO_TYPE_ICON, 2);
|
|
1478
|
+
output.writeUInt16LE(count, 4);
|
|
1479
|
+
let currentOffset = tableSize;
|
|
1480
|
+
for (let i = 0; i < count; i++) {
|
|
1481
|
+
const entry = ordered[i];
|
|
1482
|
+
const entryOffset = ICO_HEADER_SIZE + i * ICO_DIR_ENTRY_SIZE;
|
|
1483
|
+
entry.directory.copy(output, entryOffset, 0, 8);
|
|
1484
|
+
output.writeUInt32LE(entry.data.length, entryOffset + 8);
|
|
1485
|
+
output.writeUInt32LE(currentOffset, entryOffset + 12);
|
|
1486
|
+
entry.data.copy(output, currentOffset);
|
|
1487
|
+
currentOffset += entry.data.length;
|
|
1488
|
+
}
|
|
1489
|
+
return output;
|
|
1490
|
+
}
|
|
1491
|
+
async function writeIcoWithPreferredSize(sourcePath, outputPath, preferredSize) {
|
|
1492
|
+
try {
|
|
1493
|
+
const sourceBuffer = await fsExtra.readFile(sourcePath);
|
|
1494
|
+
const reordered = buildReorderedIcoBuffer(sourceBuffer, preferredSize);
|
|
1495
|
+
await fsExtra.ensureDir(path.dirname(outputPath));
|
|
1496
|
+
await fsExtra.outputFile(outputPath, reordered);
|
|
1497
|
+
return true;
|
|
1498
|
+
}
|
|
1499
|
+
catch {
|
|
1500
|
+
return false;
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1400
1504
|
const ICON_CONFIG = {
|
|
1401
1505
|
minFileSize: 100,
|
|
1402
1506
|
supportedFormats: ['png', 'ico', 'jpeg', 'jpg', 'webp', 'icns'],
|
|
@@ -1440,7 +1544,11 @@ async function copyWindowsIconIfNeeded(convertedPath, appName) {
|
|
|
1440
1544
|
try {
|
|
1441
1545
|
const finalIconPath = generateIconPath(appName);
|
|
1442
1546
|
await fsExtra.ensureDir(path.dirname(finalIconPath));
|
|
1443
|
-
|
|
1547
|
+
// Reorder ICO to prioritize 256px icons for better Windows display
|
|
1548
|
+
const reordered = await writeIcoWithPreferredSize(convertedPath, finalIconPath, 256);
|
|
1549
|
+
if (!reordered) {
|
|
1550
|
+
await fsExtra.copy(convertedPath, finalIconPath);
|
|
1551
|
+
}
|
|
1444
1552
|
return finalIconPath;
|
|
1445
1553
|
}
|
|
1446
1554
|
catch (error) {
|
|
@@ -1933,8 +2041,10 @@ const DEFAULT_PAKE_OPTIONS = {
|
|
|
1933
2041
|
enableDragDrop: false,
|
|
1934
2042
|
keepBinary: false,
|
|
1935
2043
|
multiInstance: false,
|
|
2044
|
+
multiWindow: false,
|
|
1936
2045
|
startToTray: false,
|
|
1937
2046
|
forceInternalNavigation: false,
|
|
2047
|
+
internalUrlRegex: '',
|
|
1938
2048
|
iterativeBuild: false,
|
|
1939
2049
|
zoom: 100,
|
|
1940
2050
|
minWidth: 0,
|
|
@@ -2058,12 +2168,18 @@ ${green('|_| \\__,_|_|\\_\\___| can turn any webpage into a desktop app with
|
|
|
2058
2168
|
.addOption(new Option('--multi-instance', 'Allow multiple app instances')
|
|
2059
2169
|
.default(DEFAULT_PAKE_OPTIONS.multiInstance)
|
|
2060
2170
|
.hideHelp())
|
|
2171
|
+
.addOption(new Option('--multi-window', 'Allow opening multiple windows within one app instance')
|
|
2172
|
+
.default(DEFAULT_PAKE_OPTIONS.multiWindow)
|
|
2173
|
+
.hideHelp())
|
|
2061
2174
|
.addOption(new Option('--start-to-tray', 'Start app minimized to tray')
|
|
2062
2175
|
.default(DEFAULT_PAKE_OPTIONS.startToTray)
|
|
2063
2176
|
.hideHelp())
|
|
2064
2177
|
.addOption(new Option('--force-internal-navigation', 'Keep every link inside the Pake window instead of opening external handlers')
|
|
2065
2178
|
.default(DEFAULT_PAKE_OPTIONS.forceInternalNavigation)
|
|
2066
2179
|
.hideHelp())
|
|
2180
|
+
.addOption(new Option('--internal-url-regex <string>', 'Regex pattern to match URLs that should be considered internal')
|
|
2181
|
+
.default(DEFAULT_PAKE_OPTIONS.internalUrlRegex)
|
|
2182
|
+
.hideHelp())
|
|
2067
2183
|
.addOption(new Option('--installer-language <string>', 'Installer language')
|
|
2068
2184
|
.default(DEFAULT_PAKE_OPTIONS.installerLanguage)
|
|
2069
2185
|
.hideHelp())
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pake-cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.10.0",
|
|
4
4
|
"description": "๐คฑ๐ป Turn any webpage into a desktop app with one command. ๐คฑ๐ป ไธ้ฎๆๅ
็ฝ้กต็ๆ่ฝป้ๆก้ขๅบ็จใ",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=18.0.0"
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"@rollup/plugin-replace": "^6.0.3",
|
|
73
73
|
"@rollup/plugin-terser": "^0.4.4",
|
|
74
74
|
"@types/fs-extra": "^11.0.4",
|
|
75
|
-
"@types/node": "^25.3.
|
|
75
|
+
"@types/node": "^25.3.2",
|
|
76
76
|
"@types/page-icon": "^0.3.6",
|
|
77
77
|
"@types/prompts": "^2.4.9",
|
|
78
78
|
"@types/tmp": "^0.2.6",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"app-root-path": "^3.1.0",
|
|
81
81
|
"cross-env": "^10.1.0",
|
|
82
82
|
"prettier": "^3.8.1",
|
|
83
|
-
"rollup": "^4.
|
|
83
|
+
"rollup": "^4.59.0",
|
|
84
84
|
"rollup-plugin-typescript2": "^0.36.0",
|
|
85
85
|
"tslib": "^2.8.1",
|
|
86
86
|
"typescript": "^5.9.3",
|
package/src-tauri/Cargo.lock
CHANGED
|
@@ -443,9 +443,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
|
|
443
443
|
|
|
444
444
|
[[package]]
|
|
445
445
|
name = "chrono"
|
|
446
|
-
version = "0.4.
|
|
446
|
+
version = "0.4.44"
|
|
447
447
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
448
|
-
checksum = "
|
|
448
|
+
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
|
|
449
449
|
dependencies = [
|
|
450
450
|
"iana-time-zone",
|
|
451
451
|
"num-traits",
|
|
@@ -698,9 +698,9 @@ checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376"
|
|
|
698
698
|
|
|
699
699
|
[[package]]
|
|
700
700
|
name = "deranged"
|
|
701
|
-
version = "0.5.
|
|
701
|
+
version = "0.5.8"
|
|
702
702
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
703
|
-
checksum = "
|
|
703
|
+
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
|
|
704
704
|
dependencies = [
|
|
705
705
|
"powerfmt",
|
|
706
706
|
"serde_core",
|
|
@@ -758,9 +758,9 @@ checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
|
|
|
758
758
|
|
|
759
759
|
[[package]]
|
|
760
760
|
name = "dispatch2"
|
|
761
|
-
version = "0.3.
|
|
761
|
+
version = "0.3.1"
|
|
762
762
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
763
|
-
checksum = "
|
|
763
|
+
checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"
|
|
764
764
|
dependencies = [
|
|
765
765
|
"bitflags 2.11.0",
|
|
766
766
|
"objc2",
|
|
@@ -1937,9 +1937,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
|
|
1937
1937
|
|
|
1938
1938
|
[[package]]
|
|
1939
1939
|
name = "js-sys"
|
|
1940
|
-
version = "0.3.
|
|
1940
|
+
version = "0.3.91"
|
|
1941
1941
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1942
|
-
checksum = "
|
|
1942
|
+
checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c"
|
|
1943
1943
|
dependencies = [
|
|
1944
1944
|
"once_cell",
|
|
1945
1945
|
"wasm-bindgen",
|
|
@@ -2054,9 +2054,9 @@ dependencies = [
|
|
|
2054
2054
|
|
|
2055
2055
|
[[package]]
|
|
2056
2056
|
name = "linux-raw-sys"
|
|
2057
|
-
version = "0.
|
|
2057
|
+
version = "0.12.1"
|
|
2058
2058
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2059
|
-
checksum = "
|
|
2059
|
+
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
|
|
2060
2060
|
|
|
2061
2061
|
[[package]]
|
|
2062
2062
|
name = "litemap"
|
|
@@ -2308,9 +2308,9 @@ dependencies = [
|
|
|
2308
2308
|
|
|
2309
2309
|
[[package]]
|
|
2310
2310
|
name = "objc2"
|
|
2311
|
-
version = "0.6.
|
|
2311
|
+
version = "0.6.4"
|
|
2312
2312
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2313
|
-
checksum = "
|
|
2313
|
+
checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f"
|
|
2314
2314
|
dependencies = [
|
|
2315
2315
|
"objc2-encode",
|
|
2316
2316
|
"objc2-exception-helper",
|
|
@@ -2564,7 +2564,7 @@ dependencies = [
|
|
|
2564
2564
|
|
|
2565
2565
|
[[package]]
|
|
2566
2566
|
name = "pake"
|
|
2567
|
-
version = "3.
|
|
2567
|
+
version = "3.10.0"
|
|
2568
2568
|
dependencies = [
|
|
2569
2569
|
"serde",
|
|
2570
2570
|
"serde_json",
|
|
@@ -2783,9 +2783,9 @@ dependencies = [
|
|
|
2783
2783
|
|
|
2784
2784
|
[[package]]
|
|
2785
2785
|
name = "pin-project-lite"
|
|
2786
|
-
version = "0.2.
|
|
2786
|
+
version = "0.2.17"
|
|
2787
2787
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2788
|
-
checksum = "
|
|
2788
|
+
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
|
2789
2789
|
|
|
2790
2790
|
[[package]]
|
|
2791
2791
|
name = "pin-utils"
|
|
@@ -2795,9 +2795,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
|
|
2795
2795
|
|
|
2796
2796
|
[[package]]
|
|
2797
2797
|
name = "piper"
|
|
2798
|
-
version = "0.2.
|
|
2798
|
+
version = "0.2.5"
|
|
2799
2799
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2800
|
-
checksum = "
|
|
2800
|
+
checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1"
|
|
2801
2801
|
dependencies = [
|
|
2802
2802
|
"atomic-waker",
|
|
2803
2803
|
"fastrand",
|
|
@@ -3265,9 +3265,9 @@ dependencies = [
|
|
|
3265
3265
|
|
|
3266
3266
|
[[package]]
|
|
3267
3267
|
name = "regex-syntax"
|
|
3268
|
-
version = "0.8.
|
|
3268
|
+
version = "0.8.10"
|
|
3269
3269
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3270
|
-
checksum = "
|
|
3270
|
+
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
|
3271
3271
|
|
|
3272
3272
|
[[package]]
|
|
3273
3273
|
name = "reqwest"
|
|
@@ -3377,9 +3377,9 @@ dependencies = [
|
|
|
3377
3377
|
|
|
3378
3378
|
[[package]]
|
|
3379
3379
|
name = "rustix"
|
|
3380
|
-
version = "1.1.
|
|
3380
|
+
version = "1.1.4"
|
|
3381
3381
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3382
|
-
checksum = "
|
|
3382
|
+
checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
|
|
3383
3383
|
dependencies = [
|
|
3384
3384
|
"bitflags 2.11.0",
|
|
3385
3385
|
"errno",
|
|
@@ -3390,9 +3390,9 @@ dependencies = [
|
|
|
3390
3390
|
|
|
3391
3391
|
[[package]]
|
|
3392
3392
|
name = "rustls"
|
|
3393
|
-
version = "0.23.
|
|
3393
|
+
version = "0.23.37"
|
|
3394
3394
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3395
|
-
checksum = "
|
|
3395
|
+
checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4"
|
|
3396
3396
|
dependencies = [
|
|
3397
3397
|
"once_cell",
|
|
3398
3398
|
"ring",
|
|
@@ -3638,9 +3638,9 @@ dependencies = [
|
|
|
3638
3638
|
|
|
3639
3639
|
[[package]]
|
|
3640
3640
|
name = "serde_with"
|
|
3641
|
-
version = "3.
|
|
3641
|
+
version = "3.17.0"
|
|
3642
3642
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3643
|
-
checksum = "
|
|
3643
|
+
checksum = "381b283ce7bc6b476d903296fb59d0d36633652b633b27f64db4fb46dcbfc3b9"
|
|
3644
3644
|
dependencies = [
|
|
3645
3645
|
"base64 0.22.1",
|
|
3646
3646
|
"chrono",
|
|
@@ -3657,9 +3657,9 @@ dependencies = [
|
|
|
3657
3657
|
|
|
3658
3658
|
[[package]]
|
|
3659
3659
|
name = "serde_with_macros"
|
|
3660
|
-
version = "3.
|
|
3660
|
+
version = "3.17.0"
|
|
3661
3661
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3662
|
-
checksum = "
|
|
3662
|
+
checksum = "a6d4e30573c8cb306ed6ab1dca8423eec9a463ea0e155f45399455e0368b27e0"
|
|
3663
3663
|
dependencies = [
|
|
3664
3664
|
"darling",
|
|
3665
3665
|
"proc-macro2",
|
|
@@ -4448,9 +4448,9 @@ dependencies = [
|
|
|
4448
4448
|
|
|
4449
4449
|
[[package]]
|
|
4450
4450
|
name = "tempfile"
|
|
4451
|
-
version = "3.
|
|
4451
|
+
version = "3.26.0"
|
|
4452
4452
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
4453
|
-
checksum = "
|
|
4453
|
+
checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0"
|
|
4454
4454
|
dependencies = [
|
|
4455
4455
|
"fastrand",
|
|
4456
4456
|
"getrandom 0.4.1",
|
|
@@ -5037,9 +5037,9 @@ dependencies = [
|
|
|
5037
5037
|
|
|
5038
5038
|
[[package]]
|
|
5039
5039
|
name = "wasm-bindgen"
|
|
5040
|
-
version = "0.2.
|
|
5040
|
+
version = "0.2.114"
|
|
5041
5041
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
5042
|
-
checksum = "
|
|
5042
|
+
checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e"
|
|
5043
5043
|
dependencies = [
|
|
5044
5044
|
"cfg-if",
|
|
5045
5045
|
"once_cell",
|
|
@@ -5050,9 +5050,9 @@ dependencies = [
|
|
|
5050
5050
|
|
|
5051
5051
|
[[package]]
|
|
5052
5052
|
name = "wasm-bindgen-futures"
|
|
5053
|
-
version = "0.4.
|
|
5053
|
+
version = "0.4.64"
|
|
5054
5054
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
5055
|
-
checksum = "
|
|
5055
|
+
checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8"
|
|
5056
5056
|
dependencies = [
|
|
5057
5057
|
"cfg-if",
|
|
5058
5058
|
"futures-util",
|
|
@@ -5064,9 +5064,9 @@ dependencies = [
|
|
|
5064
5064
|
|
|
5065
5065
|
[[package]]
|
|
5066
5066
|
name = "wasm-bindgen-macro"
|
|
5067
|
-
version = "0.2.
|
|
5067
|
+
version = "0.2.114"
|
|
5068
5068
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
5069
|
-
checksum = "
|
|
5069
|
+
checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6"
|
|
5070
5070
|
dependencies = [
|
|
5071
5071
|
"quote",
|
|
5072
5072
|
"wasm-bindgen-macro-support",
|
|
@@ -5074,9 +5074,9 @@ dependencies = [
|
|
|
5074
5074
|
|
|
5075
5075
|
[[package]]
|
|
5076
5076
|
name = "wasm-bindgen-macro-support"
|
|
5077
|
-
version = "0.2.
|
|
5077
|
+
version = "0.2.114"
|
|
5078
5078
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
5079
|
-
checksum = "
|
|
5079
|
+
checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3"
|
|
5080
5080
|
dependencies = [
|
|
5081
5081
|
"bumpalo",
|
|
5082
5082
|
"proc-macro2",
|
|
@@ -5087,9 +5087,9 @@ dependencies = [
|
|
|
5087
5087
|
|
|
5088
5088
|
[[package]]
|
|
5089
5089
|
name = "wasm-bindgen-shared"
|
|
5090
|
-
version = "0.2.
|
|
5090
|
+
version = "0.2.114"
|
|
5091
5091
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
5092
|
-
checksum = "
|
|
5092
|
+
checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16"
|
|
5093
5093
|
dependencies = [
|
|
5094
5094
|
"unicode-ident",
|
|
5095
5095
|
]
|
|
@@ -5143,9 +5143,9 @@ dependencies = [
|
|
|
5143
5143
|
|
|
5144
5144
|
[[package]]
|
|
5145
5145
|
name = "web-sys"
|
|
5146
|
-
version = "0.3.
|
|
5146
|
+
version = "0.3.91"
|
|
5147
5147
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
5148
|
-
checksum = "
|
|
5148
|
+
checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9"
|
|
5149
5149
|
dependencies = [
|
|
5150
5150
|
"js-sys",
|
|
5151
5151
|
"wasm-bindgen",
|
|
@@ -5931,9 +5931,9 @@ dependencies = [
|
|
|
5931
5931
|
|
|
5932
5932
|
[[package]]
|
|
5933
5933
|
name = "zbus"
|
|
5934
|
-
version = "5.
|
|
5934
|
+
version = "5.14.0"
|
|
5935
5935
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
5936
|
-
checksum = "
|
|
5936
|
+
checksum = "ca82f95dbd3943a40a53cfded6c2d0a2ca26192011846a1810c4256ef92c60bc"
|
|
5937
5937
|
dependencies = [
|
|
5938
5938
|
"async-broadcast",
|
|
5939
5939
|
"async-executor",
|
|
@@ -5966,9 +5966,9 @@ dependencies = [
|
|
|
5966
5966
|
|
|
5967
5967
|
[[package]]
|
|
5968
5968
|
name = "zbus_macros"
|
|
5969
|
-
version = "5.
|
|
5969
|
+
version = "5.14.0"
|
|
5970
5970
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
5971
|
-
checksum = "
|
|
5971
|
+
checksum = "897e79616e84aac4b2c46e9132a4f63b93105d54fe8c0e8f6bffc21fa8d49222"
|
|
5972
5972
|
dependencies = [
|
|
5973
5973
|
"proc-macro-crate 3.4.0",
|
|
5974
5974
|
"proc-macro2",
|
|
@@ -5992,18 +5992,18 @@ dependencies = [
|
|
|
5992
5992
|
|
|
5993
5993
|
[[package]]
|
|
5994
5994
|
name = "zerocopy"
|
|
5995
|
-
version = "0.8.
|
|
5995
|
+
version = "0.8.40"
|
|
5996
5996
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
5997
|
-
checksum = "
|
|
5997
|
+
checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5"
|
|
5998
5998
|
dependencies = [
|
|
5999
5999
|
"zerocopy-derive",
|
|
6000
6000
|
]
|
|
6001
6001
|
|
|
6002
6002
|
[[package]]
|
|
6003
6003
|
name = "zerocopy-derive"
|
|
6004
|
-
version = "0.8.
|
|
6004
|
+
version = "0.8.40"
|
|
6005
6005
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
6006
|
-
checksum = "
|
|
6006
|
+
checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953"
|
|
6007
6007
|
dependencies = [
|
|
6008
6008
|
"proc-macro2",
|
|
6009
6009
|
"quote",
|
|
@@ -6078,9 +6078,9 @@ checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
|
|
6078
6078
|
|
|
6079
6079
|
[[package]]
|
|
6080
6080
|
name = "zvariant"
|
|
6081
|
-
version = "5.
|
|
6081
|
+
version = "5.10.0"
|
|
6082
6082
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
6083
|
-
checksum = "
|
|
6083
|
+
checksum = "5708299b21903bbe348e94729f22c49c55d04720a004aa350f1f9c122fd2540b"
|
|
6084
6084
|
dependencies = [
|
|
6085
6085
|
"endi",
|
|
6086
6086
|
"enumflags2",
|
|
@@ -6092,9 +6092,9 @@ dependencies = [
|
|
|
6092
6092
|
|
|
6093
6093
|
[[package]]
|
|
6094
6094
|
name = "zvariant_derive"
|
|
6095
|
-
version = "5.
|
|
6095
|
+
version = "5.10.0"
|
|
6096
6096
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
6097
|
-
checksum = "
|
|
6097
|
+
checksum = "5b59b012ebe9c46656f9cc08d8da8b4c726510aef12559da3e5f1bf72780752c"
|
|
6098
6098
|
dependencies = [
|
|
6099
6099
|
"proc-macro-crate 3.4.0",
|
|
6100
6100
|
"proc-macro2",
|
package/src-tauri/Cargo.toml
CHANGED
|
Binary file
|
package/src-tauri/pake.json
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"maximize": false,
|
|
20
20
|
"start_to_tray": false,
|
|
21
21
|
"force_internal_navigation": false,
|
|
22
|
+
"internal_url_regex": "",
|
|
22
23
|
"new_window": false
|
|
23
24
|
}
|
|
24
25
|
],
|
|
@@ -35,5 +36,6 @@
|
|
|
35
36
|
"system_tray_path": "icons/icon.png",
|
|
36
37
|
"inject": [],
|
|
37
38
|
"proxy_url": "",
|
|
38
|
-
"multi_instance": false
|
|
39
|
+
"multi_instance": false,
|
|
40
|
+
"multi_window": false
|
|
39
41
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
use serde::{Deserialize, Serialize};
|
|
2
2
|
|
|
3
|
-
#[derive(Debug, Serialize, Deserialize)]
|
|
3
|
+
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
4
4
|
pub struct WindowConfig {
|
|
5
5
|
pub url: String,
|
|
6
6
|
pub hide_title_bar: bool,
|
|
@@ -24,6 +24,8 @@ pub struct WindowConfig {
|
|
|
24
24
|
pub start_to_tray: bool,
|
|
25
25
|
#[serde(default)]
|
|
26
26
|
pub force_internal_navigation: bool,
|
|
27
|
+
#[serde(default)]
|
|
28
|
+
pub internal_url_regex: String,
|
|
27
29
|
#[serde(default = "default_zoom")]
|
|
28
30
|
pub zoom: u32,
|
|
29
31
|
#[serde(default)]
|
|
@@ -38,7 +40,7 @@ fn default_zoom() -> u32 {
|
|
|
38
40
|
100
|
|
39
41
|
}
|
|
40
42
|
|
|
41
|
-
#[derive(Debug, Serialize, Deserialize)]
|
|
43
|
+
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
42
44
|
pub struct PlatformSpecific<T> {
|
|
43
45
|
pub macos: T,
|
|
44
46
|
pub linux: T,
|
|
@@ -70,7 +72,7 @@ where
|
|
|
70
72
|
pub type UserAgent = PlatformSpecific<String>;
|
|
71
73
|
pub type FunctionON = PlatformSpecific<bool>;
|
|
72
74
|
|
|
73
|
-
#[derive(Debug, Serialize, Deserialize)]
|
|
75
|
+
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
74
76
|
pub struct PakeConfig {
|
|
75
77
|
pub windows: Vec<WindowConfig>,
|
|
76
78
|
pub user_agent: UserAgent,
|
|
@@ -79,6 +81,8 @@ pub struct PakeConfig {
|
|
|
79
81
|
pub proxy_url: String,
|
|
80
82
|
#[serde(default)]
|
|
81
83
|
pub multi_instance: bool,
|
|
84
|
+
#[serde(default)]
|
|
85
|
+
pub multi_window: bool,
|
|
82
86
|
}
|
|
83
87
|
|
|
84
88
|
impl PakeConfig {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// Menu functionality is only used on macOS
|
|
2
2
|
#![cfg(target_os = "macos")]
|
|
3
3
|
|
|
4
|
+
use crate::app::window::open_additional_window_safe;
|
|
4
5
|
use tauri::menu::{AboutMetadata, Menu, MenuItem, PredefinedMenuItem, Submenu};
|
|
5
6
|
use tauri::{AppHandle, Manager, Wry};
|
|
6
7
|
use tauri_plugin_opener::OpenerExt;
|
|
7
8
|
|
|
8
|
-
pub fn get_menu(app: &AppHandle<Wry
|
|
9
|
+
pub fn get_menu(app: &AppHandle<Wry>, allow_multi_window: bool) -> tauri::Result<Menu<Wry>> {
|
|
9
10
|
let pake_version = env!("CARGO_PKG_VERSION");
|
|
10
11
|
let pake_menu_item_title = format!("Built with Pake V{}", pake_version);
|
|
11
12
|
|
|
@@ -13,7 +14,7 @@ pub fn get_menu(app: &AppHandle<Wry>) -> tauri::Result<Menu<Wry>> {
|
|
|
13
14
|
app,
|
|
14
15
|
&[
|
|
15
16
|
&app_menu(app)?,
|
|
16
|
-
&file_menu(app)?,
|
|
17
|
+
&file_menu(app, allow_multi_window)?,
|
|
17
18
|
&edit_menu(app)?,
|
|
18
19
|
&view_menu(app)?,
|
|
19
20
|
&navigation_menu(app)?,
|
|
@@ -44,8 +45,18 @@ fn app_menu(app: &AppHandle<Wry>) -> tauri::Result<Submenu<Wry>> {
|
|
|
44
45
|
Ok(app_menu)
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
fn file_menu(app: &AppHandle<Wry
|
|
48
|
+
fn file_menu(app: &AppHandle<Wry>, allow_multi_window: bool) -> tauri::Result<Submenu<Wry>> {
|
|
48
49
|
let file_menu = Submenu::new(app, "File", true)?;
|
|
50
|
+
if allow_multi_window {
|
|
51
|
+
file_menu.append(&MenuItem::with_id(
|
|
52
|
+
app,
|
|
53
|
+
"new_window",
|
|
54
|
+
"New Window",
|
|
55
|
+
true,
|
|
56
|
+
Some("CmdOrCtrl+N"),
|
|
57
|
+
)?)?;
|
|
58
|
+
file_menu.append(&PredefinedMenuItem::separator(app)?)?;
|
|
59
|
+
}
|
|
49
60
|
file_menu.append(&PredefinedMenuItem::close_window(app, None)?)?;
|
|
50
61
|
file_menu.append(&PredefinedMenuItem::separator(app)?)?;
|
|
51
62
|
file_menu.append(&MenuItem::with_id(
|
|
@@ -181,6 +192,9 @@ fn help_menu(app: &AppHandle<Wry>, title: &str) -> tauri::Result<Submenu<Wry>> {
|
|
|
181
192
|
|
|
182
193
|
pub fn handle_menu_click(app_handle: &AppHandle, id: &str) {
|
|
183
194
|
match id {
|
|
195
|
+
"new_window" => {
|
|
196
|
+
open_additional_window_safe(app_handle);
|
|
197
|
+
}
|
|
184
198
|
"pake_github_link" => {
|
|
185
199
|
let _ = app_handle
|
|
186
200
|
.opener()
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
use crate::app::window::open_additional_window_safe;
|
|
1
2
|
use std::str::FromStr;
|
|
2
3
|
use std::sync::{Arc, Mutex};
|
|
3
4
|
use std::time::{Duration, Instant};
|
|
@@ -14,25 +15,36 @@ pub fn set_system_tray(
|
|
|
14
15
|
show_system_tray: bool,
|
|
15
16
|
tray_icon_path: &str,
|
|
16
17
|
_init_fullscreen: bool,
|
|
18
|
+
allow_multi_window: bool,
|
|
17
19
|
) -> tauri::Result<()> {
|
|
18
20
|
if !show_system_tray {
|
|
19
21
|
app.remove_tray_by_id("pake-tray");
|
|
20
22
|
return Ok(());
|
|
21
23
|
}
|
|
22
24
|
|
|
25
|
+
let new_window = MenuItemBuilder::with_id("new_window", "New Window").build(app)?;
|
|
23
26
|
let hide_app = MenuItemBuilder::with_id("hide_app", "Hide").build(app)?;
|
|
24
27
|
let show_app = MenuItemBuilder::with_id("show_app", "Show").build(app)?;
|
|
25
28
|
let quit = MenuItemBuilder::with_id("quit", "Quit").build(app)?;
|
|
26
29
|
|
|
27
|
-
let menu =
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
let menu = if allow_multi_window {
|
|
31
|
+
MenuBuilder::new(app)
|
|
32
|
+
.items(&[&new_window, &hide_app, &show_app, &quit])
|
|
33
|
+
.build()?
|
|
34
|
+
} else {
|
|
35
|
+
MenuBuilder::new(app)
|
|
36
|
+
.items(&[&hide_app, &show_app, &quit])
|
|
37
|
+
.build()?
|
|
38
|
+
};
|
|
30
39
|
|
|
31
40
|
app.app_handle().remove_tray_by_id("pake-tray");
|
|
32
41
|
|
|
33
42
|
let tray = TrayIconBuilder::new()
|
|
34
43
|
.menu(&menu)
|
|
35
44
|
.on_menu_event(move |app, event| match event.id().as_ref() {
|
|
45
|
+
"new_window" => {
|
|
46
|
+
open_additional_window_safe(app);
|
|
47
|
+
}
|
|
36
48
|
"hide_app" => {
|
|
37
49
|
if let Some(window) = app.get_webview_window("pake") {
|
|
38
50
|
window.minimize().unwrap();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
use crate::app::config::PakeConfig;
|
|
2
2
|
use crate::util::get_data_dir;
|
|
3
|
-
use std::{path::PathBuf, str::FromStr};
|
|
4
|
-
use tauri::{
|
|
3
|
+
use std::{path::PathBuf, str::FromStr, sync::Mutex};
|
|
4
|
+
use tauri::{AppHandle, Config, Manager, Url, WebviewUrl, WebviewWindow, WebviewWindowBuilder};
|
|
5
5
|
|
|
6
6
|
#[cfg(target_os = "macos")]
|
|
7
7
|
use tauri::{Theme, TitleBarStyle};
|
|
@@ -22,9 +22,67 @@ fn build_proxy_browser_arg(url: &Url) -> Option<String> {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
pub
|
|
25
|
+
pub struct MultiWindowState {
|
|
26
|
+
pub pake_config: PakeConfig,
|
|
27
|
+
pub tauri_config: Config,
|
|
28
|
+
next_window_index: Mutex<u32>,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
impl MultiWindowState {
|
|
32
|
+
pub fn new(pake_config: PakeConfig, tauri_config: Config) -> Self {
|
|
33
|
+
Self {
|
|
34
|
+
pake_config,
|
|
35
|
+
tauri_config,
|
|
36
|
+
next_window_index: Mutex::new(0),
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
fn next_window_label(&self) -> String {
|
|
41
|
+
let mut index = self.next_window_index.lock().unwrap();
|
|
42
|
+
*index += 1;
|
|
43
|
+
format!("pake-{}", *index)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
pub fn set_window(app: &AppHandle, config: &PakeConfig, tauri_config: &Config) -> WebviewWindow {
|
|
48
|
+
build_window_with_label(app, config, tauri_config, "pake").expect("Failed to build window")
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
pub fn open_additional_window(app: &AppHandle) -> tauri::Result<WebviewWindow> {
|
|
52
|
+
let state = app.state::<MultiWindowState>();
|
|
53
|
+
let label = state.next_window_label();
|
|
54
|
+
build_window_with_label(app, &state.pake_config, &state.tauri_config, &label)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
pub fn open_additional_window_safe(app: &AppHandle) {
|
|
58
|
+
#[cfg(target_os = "windows")]
|
|
59
|
+
{
|
|
60
|
+
let app_handle = app.clone();
|
|
61
|
+
std::thread::spawn(move || {
|
|
62
|
+
if let Ok(window) = open_additional_window(&app_handle) {
|
|
63
|
+
let _ = window.show();
|
|
64
|
+
let _ = window.set_focus();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
#[cfg(not(target_os = "windows"))]
|
|
70
|
+
{
|
|
71
|
+
if let Ok(window) = open_additional_window(app) {
|
|
72
|
+
let _ = window.show();
|
|
73
|
+
let _ = window.set_focus();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
fn build_window_with_label(
|
|
79
|
+
app: &AppHandle,
|
|
80
|
+
config: &PakeConfig,
|
|
81
|
+
tauri_config: &Config,
|
|
82
|
+
label: &str,
|
|
83
|
+
) -> tauri::Result<WebviewWindow> {
|
|
26
84
|
let package_name = tauri_config.clone().product_name.unwrap();
|
|
27
|
-
let _data_dir = get_data_dir(app
|
|
85
|
+
let _data_dir = get_data_dir(app, package_name);
|
|
28
86
|
|
|
29
87
|
let window_config = config
|
|
30
88
|
.windows
|
|
@@ -53,7 +111,7 @@ pub fn set_window(app: &mut App, config: &PakeConfig, tauri_config: &Config) ->
|
|
|
53
111
|
}
|
|
54
112
|
});
|
|
55
113
|
|
|
56
|
-
let mut window_builder = WebviewWindowBuilder::new(app,
|
|
114
|
+
let mut window_builder = WebviewWindowBuilder::new(app, label, url)
|
|
57
115
|
.title(effective_title)
|
|
58
116
|
.visible(false)
|
|
59
117
|
.user_agent(user_agent)
|
|
@@ -269,5 +327,5 @@ pub fn set_window(app: &mut App, config: &PakeConfig, tauri_config: &Config) ->
|
|
|
269
327
|
true
|
|
270
328
|
});
|
|
271
329
|
|
|
272
|
-
window_builder.build()
|
|
330
|
+
window_builder.build()
|
|
273
331
|
}
|
|
@@ -262,6 +262,15 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
262
262
|
const invoke = tauri.core.invoke;
|
|
263
263
|
const pakeConfig = window["pakeConfig"] || {};
|
|
264
264
|
const forceInternalNavigation = pakeConfig.force_internal_navigation === true;
|
|
265
|
+
const internalUrlRegex = pakeConfig.internal_url_regex || "";
|
|
266
|
+
let internalUrlPattern = null;
|
|
267
|
+
if (internalUrlRegex) {
|
|
268
|
+
try {
|
|
269
|
+
internalUrlPattern = new RegExp(internalUrlRegex);
|
|
270
|
+
} catch (e) {
|
|
271
|
+
console.error("[Pake] Invalid internal_url_regex pattern:", e);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
265
274
|
|
|
266
275
|
if (!document.getElementById("pake-top-dom")) {
|
|
267
276
|
const topDom = document.createElement("div");
|
|
@@ -465,6 +474,22 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
465
474
|
}
|
|
466
475
|
};
|
|
467
476
|
|
|
477
|
+
// Check if URL should be treated as internal based on regex pattern or domain
|
|
478
|
+
const isInternalUrl = (url) => {
|
|
479
|
+
// If regex pattern is configured, use it as the primary check
|
|
480
|
+
if (internalUrlPattern) {
|
|
481
|
+
try {
|
|
482
|
+
return internalUrlPattern.test(url);
|
|
483
|
+
} catch (e) {
|
|
484
|
+
console.error("[Pake] Error testing internal_url_regex:", e);
|
|
485
|
+
// Fall back to domain check on error
|
|
486
|
+
return isSameDomain(url);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
// Default to domain-based check
|
|
490
|
+
return isSameDomain(url);
|
|
491
|
+
};
|
|
492
|
+
|
|
468
493
|
const detectAnchorElementClick = (e) => {
|
|
469
494
|
// Safety check: ensure e.target exists and is an Element with closest method
|
|
470
495
|
if (!e.target || typeof e.target.closest !== "function") {
|
|
@@ -493,8 +518,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
493
518
|
return;
|
|
494
519
|
}
|
|
495
520
|
|
|
496
|
-
if (
|
|
497
|
-
// For
|
|
521
|
+
if (isInternalUrl(absoluteUrl)) {
|
|
522
|
+
// For internal links (based on regex or domain), let the browser handle it naturally
|
|
498
523
|
return;
|
|
499
524
|
}
|
|
500
525
|
|
|
@@ -537,7 +562,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
537
562
|
return;
|
|
538
563
|
}
|
|
539
564
|
|
|
540
|
-
// Handle regular links:
|
|
565
|
+
// Handle regular links: internal URLs allow normal navigation, external opens new window
|
|
541
566
|
if (!target || target === "_self") {
|
|
542
567
|
// Optimization: Allow previewable media to be handled by the app/browser directly
|
|
543
568
|
// This fixes issues where CDN links are treated as external
|
|
@@ -545,7 +570,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
545
570
|
return;
|
|
546
571
|
}
|
|
547
572
|
|
|
548
|
-
if (!
|
|
573
|
+
if (!isInternalUrl(absoluteUrl)) {
|
|
549
574
|
if (forceInternalNavigation) {
|
|
550
575
|
return;
|
|
551
576
|
}
|
|
@@ -583,7 +608,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
583
608
|
const hrefUrl = new URL(url, baseUrl);
|
|
584
609
|
const absoluteUrl = hrefUrl.href;
|
|
585
610
|
|
|
586
|
-
if (!
|
|
611
|
+
if (!isInternalUrl(absoluteUrl)) {
|
|
587
612
|
if (forceInternalNavigation) {
|
|
588
613
|
return originalWindowOpen.call(window, absoluteUrl, name, specs);
|
|
589
614
|
}
|
package/src-tauri/src/lib.rs
CHANGED
|
@@ -17,7 +17,7 @@ use app::{
|
|
|
17
17
|
update_theme_mode,
|
|
18
18
|
},
|
|
19
19
|
setup::{set_global_shortcut, set_system_tray},
|
|
20
|
-
window::set_window,
|
|
20
|
+
window::{open_additional_window_safe, set_window, MultiWindowState},
|
|
21
21
|
};
|
|
22
22
|
use util::get_pake_config;
|
|
23
23
|
|
|
@@ -38,6 +38,7 @@ pub fn run_app() {
|
|
|
38
38
|
let init_fullscreen = pake_config.windows[0].fullscreen;
|
|
39
39
|
let start_to_tray = pake_config.windows[0].start_to_tray && show_system_tray; // Only valid when tray is enabled
|
|
40
40
|
let multi_instance = pake_config.multi_instance;
|
|
41
|
+
let multi_window = pake_config.multi_window;
|
|
41
42
|
|
|
42
43
|
let window_state_plugin = WindowStatePlugin::default()
|
|
43
44
|
.with_state_flags(if init_fullscreen {
|
|
@@ -59,13 +60,17 @@ pub fn run_app() {
|
|
|
59
60
|
|
|
60
61
|
// Only add single instance plugin if multiple instances are not allowed
|
|
61
62
|
if !multi_instance {
|
|
62
|
-
app_builder = app_builder.plugin(tauri_plugin_single_instance::init(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
let
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
app_builder = app_builder.plugin(tauri_plugin_single_instance::init(
|
|
64
|
+
move |app, _args, _cwd| {
|
|
65
|
+
if multi_window {
|
|
66
|
+
open_additional_window_safe(app);
|
|
67
|
+
} else if let Some(window) = app.get_webview_window("pake") {
|
|
68
|
+
let _ = window.unminimize();
|
|
69
|
+
let _ = window.show();
|
|
70
|
+
let _ = window.set_focus();
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
));
|
|
69
74
|
}
|
|
70
75
|
|
|
71
76
|
app_builder
|
|
@@ -77,10 +82,15 @@ pub fn run_app() {
|
|
|
77
82
|
clear_cache_and_restart,
|
|
78
83
|
])
|
|
79
84
|
.setup(move |app| {
|
|
85
|
+
app.manage(MultiWindowState::new(
|
|
86
|
+
pake_config.clone(),
|
|
87
|
+
tauri_config.clone(),
|
|
88
|
+
));
|
|
89
|
+
|
|
80
90
|
// --- Menu Construction Start ---
|
|
81
91
|
#[cfg(target_os = "macos")]
|
|
82
92
|
{
|
|
83
|
-
let menu = app::menu::get_menu(app.app_handle())?;
|
|
93
|
+
let menu = app::menu::get_menu(app.app_handle(), multi_window)?;
|
|
84
94
|
app.set_menu(menu)?;
|
|
85
95
|
|
|
86
96
|
// Event Handling for Custom Menu Item
|
|
@@ -90,12 +100,13 @@ pub fn run_app() {
|
|
|
90
100
|
}
|
|
91
101
|
// --- Menu Construction End ---
|
|
92
102
|
|
|
93
|
-
let window = set_window(app, &pake_config, &tauri_config);
|
|
103
|
+
let window = set_window(app.app_handle(), &pake_config, &tauri_config);
|
|
94
104
|
set_system_tray(
|
|
95
105
|
app.app_handle(),
|
|
96
106
|
show_system_tray,
|
|
97
107
|
&pake_config.system_tray_path,
|
|
98
108
|
init_fullscreen,
|
|
109
|
+
multi_window,
|
|
99
110
|
)
|
|
100
111
|
.unwrap();
|
|
101
112
|
set_global_shortcut(app.app_handle(), activation_shortcut, init_fullscreen).unwrap();
|
|
@@ -130,7 +141,7 @@ pub fn run_app() {
|
|
|
130
141
|
})
|
|
131
142
|
.on_window_event(move |_window, _event| {
|
|
132
143
|
if let tauri::WindowEvent::CloseRequested { api, .. } = _event {
|
|
133
|
-
if hide_on_close {
|
|
144
|
+
if hide_on_close && _window.label() == "pake" {
|
|
134
145
|
// Hide window when hide_on_close is enabled (regardless of tray status)
|
|
135
146
|
let window = _window.clone();
|
|
136
147
|
tauri::async_runtime::spawn(async move {
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"windows": [
|
|
3
|
-
{
|
|
4
|
-
"url": "https://twitter.com/",
|
|
5
|
-
"url_type": "web",
|
|
6
|
-
"hide_title_bar": false,
|
|
7
|
-
"fullscreen": false,
|
|
8
|
-
"width": 1200,
|
|
9
|
-
"height": 780,
|
|
10
|
-
"resizable": true,
|
|
11
|
-
"always_on_top": false,
|
|
12
|
-
"dark_mode": false,
|
|
13
|
-
"activation_shortcut": "",
|
|
14
|
-
"disabled_web_shortcuts": false,
|
|
15
|
-
"hide_on_close": true,
|
|
16
|
-
"incognito": false,
|
|
17
|
-
"enable_wasm": false,
|
|
18
|
-
"enable_drag_drop": false,
|
|
19
|
-
"maximize": false,
|
|
20
|
-
"start_to_tray": false,
|
|
21
|
-
"force_internal_navigation": false,
|
|
22
|
-
"new_window": false,
|
|
23
|
-
"zoom": 100,
|
|
24
|
-
"min_width": 0,
|
|
25
|
-
"min_height": 0,
|
|
26
|
-
"ignore_certificate_errors": false
|
|
27
|
-
}
|
|
28
|
-
],
|
|
29
|
-
"user_agent": {
|
|
30
|
-
"macos": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.2 Safari/605.1.15",
|
|
31
|
-
"linux": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
|
|
32
|
-
"windows": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"
|
|
33
|
-
},
|
|
34
|
-
"system_tray": {
|
|
35
|
-
"macos": false,
|
|
36
|
-
"linux": true,
|
|
37
|
-
"windows": true
|
|
38
|
-
},
|
|
39
|
-
"system_tray_path": "png/icon_512.png",
|
|
40
|
-
"inject": [],
|
|
41
|
-
"proxy_url": "",
|
|
42
|
-
"multi_instance": false
|
|
43
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"productName": "twitter",
|
|
3
|
-
"identifier": "com.pake.4fd9c9",
|
|
4
|
-
"version": "1.0.0",
|
|
5
|
-
"app": {
|
|
6
|
-
"withGlobalTauri": true,
|
|
7
|
-
"security": {
|
|
8
|
-
"headers": {},
|
|
9
|
-
"csp": null
|
|
10
|
-
}
|
|
11
|
-
},
|
|
12
|
-
"build": {
|
|
13
|
-
"frontendDist": "../dist"
|
|
14
|
-
},
|
|
15
|
-
"bundle": {
|
|
16
|
-
"icon": [
|
|
17
|
-
"icons/icon.icns"
|
|
18
|
-
],
|
|
19
|
-
"active": true,
|
|
20
|
-
"targets": [
|
|
21
|
-
"app"
|
|
22
|
-
],
|
|
23
|
-
"macOS": {
|
|
24
|
-
"signingIdentity": "-",
|
|
25
|
-
"hardenedRuntime": true,
|
|
26
|
-
"dmg": {
|
|
27
|
-
"background": "assets/macos/dmg/background.png",
|
|
28
|
-
"windowSize": {
|
|
29
|
-
"width": 680,
|
|
30
|
-
"height": 420
|
|
31
|
-
},
|
|
32
|
-
"appPosition": {
|
|
33
|
-
"x": 190,
|
|
34
|
-
"y": 250
|
|
35
|
-
},
|
|
36
|
-
"applicationFolderPosition": {
|
|
37
|
-
"x": 500,
|
|
38
|
-
"y": 250
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
"mainBinaryName": "pake-twitter"
|
|
44
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"bundle": {
|
|
3
|
-
"icon": [
|
|
4
|
-
"icons/icon.icns"
|
|
5
|
-
],
|
|
6
|
-
"active": true,
|
|
7
|
-
"targets": [
|
|
8
|
-
"app"
|
|
9
|
-
],
|
|
10
|
-
"macOS": {
|
|
11
|
-
"signingIdentity": "-",
|
|
12
|
-
"hardenedRuntime": true,
|
|
13
|
-
"dmg": {
|
|
14
|
-
"background": "assets/macos/dmg/background.png",
|
|
15
|
-
"windowSize": {
|
|
16
|
-
"width": 680,
|
|
17
|
-
"height": 420
|
|
18
|
-
},
|
|
19
|
-
"appPosition": {
|
|
20
|
-
"x": 190,
|
|
21
|
-
"y": 250
|
|
22
|
-
},
|
|
23
|
-
"applicationFolderPosition": {
|
|
24
|
-
"x": 500,
|
|
25
|
-
"y": 250
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"bundle": {
|
|
3
|
-
"icon": ["png/weekly_256.ico", "png/weekly_32.ico"],
|
|
4
|
-
"active": true,
|
|
5
|
-
"resources": ["png/weekly_32.ico"],
|
|
6
|
-
"targets": ["msi"],
|
|
7
|
-
"windows": {
|
|
8
|
-
"digestAlgorithm": "sha256",
|
|
9
|
-
"wix": {
|
|
10
|
-
"language": ["en-US"],
|
|
11
|
-
"template": "assets/main.wxs"
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}
|