@bobfrankston/msger 0.1.74 → 0.1.75
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/KNOWN-BUGS.md +121 -0
- package/MSGER-API-SUMMARY.md +162 -0
- package/MSGER-API.md +376 -0
- package/README.md +93 -0
- package/SESSION-2025-11-06.md +191 -0
- package/SESSION-NOTES.md +678 -0
- package/clihandler.d.ts.map +1 -1
- package/clihandler.js +62 -2
- package/clihandler.js.map +1 -1
- package/clihandler.ts +60 -2
- package/icon.png +0 -0
- package/icon1.png +0 -0
- package/msger-native/Cargo.toml +1 -0
- package/msger-native/bin/msgernative.exe +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Breadcrumbs +12 -118
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/BrowserMetrics/{BrowserMetrics-690552AF-DCD4.pma → BrowserMetrics-690B9AD3-657C.pma} +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/BrowserMetrics/{BrowserMetrics-69055373-F88C.pma → BrowserMetrics-690BA05A-501C.pma} +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Crashpad/settings.dat +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/BrowsingTopicsState +1 -1
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Cache/Cache_Data/data_0 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Cache/Cache_Data/data_1 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/{BrowserMetrics/BrowserMetrics-69055587-A65C.pma → Default/Cache/Cache_Data/data_2} +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Cache/Cache_Data/data_3 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Cache/Cache_Data/f_000001 +383 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Cache/Cache_Data/f_000002 +1091 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Cache/Cache_Data/f_000003 +2153 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Cache/Cache_Data/f_000004 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Cache/Cache_Data/f_000005 +626 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Cache/Cache_Data/f_000006 +393 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Cache/Cache_Data/index +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Code Cache/js/01241693cfdc32b9_0 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Code Cache/js/0ba1eea781f3552c_0 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Code Cache/js/323aa210eebefe2c_0 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Code Cache/js/4608446ac118e77a_0 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Code Cache/js/6938205dc2f77841_0 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Code Cache/js/6de12299dc89e5f3_0 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Code Cache/js/8f403c112eaa455b_0 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Code Cache/js/9a3aceb491137f07_0 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Code Cache/js/aedb266cbaf9c28f_0 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Code Cache/js/ca526fdda86d0b9d_0 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Code Cache/js/f5d11d783c9fdf69_0 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Code Cache/js/index-dir/the-real-index +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Collections/collectionsSQLite +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Collections/collectionsSQLite-journal +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/DIPS +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/DawnGraphiteCache/data_1 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/DawnGraphiteCache/index +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/DawnWebGPUCache/data_1 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/DawnWebGPUCache/index +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Extension State/LOG +3 -3
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Extension State/LOG.old +3 -3
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Favicons +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/GPUCache/data_0 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/GPUCache/data_1 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/GPUCache/data_2 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/GPUCache/index +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/History +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Local Storage/leveldb/000003.log +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Local Storage/leveldb/LOG +3 -3
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Local Storage/leveldb/LOG.old +3 -3
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/MediaDeviceSalts +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/MediaDeviceSalts-journal +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Network/Network Persistent State +1 -1
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Network/TransportSecurity +1 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Preferences +1 -1
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Service Worker/CacheStorage/14e849fa8522d406112ea607cf7fd6342b71b987/249ee9af-c3df-4a86-89a8-2c51f3370ee0/index +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Service Worker/CacheStorage/14e849fa8522d406112ea607cf7fd6342b71b987/249ee9af-c3df-4a86-89a8-2c51f3370ee0/index-dir/the-real-index +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Service Worker/CacheStorage/14e849fa8522d406112ea607cf7fd6342b71b987/index.txt +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Service Worker/Database/000003.log +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Service Worker/Database/CURRENT +1 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Service Worker/Database/LOCK +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Service Worker/Database/LOG +3 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Service Worker/Database/LOG.old +3 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Service Worker/Database/MANIFEST-000001 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Service Worker/ScriptCache/2cc80dabc69f58b6_0 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Service Worker/ScriptCache/2cc80dabc69f58b6_1 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Service Worker/ScriptCache/index +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Service Worker/ScriptCache/index-dir/the-real-index +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Session Storage/000003.log +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Session Storage/LOG +3 -3
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Session Storage/LOG.old +3 -3
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Site Characteristics Database/000003.log +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Site Characteristics Database/LOG +3 -3
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Site Characteristics Database/LOG.old +3 -3
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Sync Data/LevelDB/LOG +3 -3
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/Sync Data/LevelDB/LOG.old +3 -3
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/WebStorage/QuotaManager +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/WebStorage/QuotaManager-journal +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/favorites_diagnostic.log +27 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/shared_proto_db/000003.log +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/shared_proto_db/LOG +3 -3
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/shared_proto_db/LOG.old +3 -3
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/shared_proto_db/metadata/000003.log +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/shared_proto_db/metadata/LOG +3 -3
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Default/shared_proto_db/metadata/LOG.old +3 -3
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/GrShaderCache/data_0 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/GrShaderCache/data_1 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/GrShaderCache/data_3 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/GrShaderCache/f_000003 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/GrShaderCache/f_000004 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/GrShaderCache/index +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/GraphiteDawnCache/data_1 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/GraphiteDawnCache/index +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/Local State +1 -1
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/RevisitationBloomfilter +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/ShaderCache/data_1 +0 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/ShaderCache/index +0 -0
- package/msger-native/src/main.rs +343 -37
- package/msger-native/src/template.html +103 -28
- package/msger-storage-demo.html +290 -0
- package/msger.code-workspace +3 -0
- package/msgerdefs/README.md +122 -0
- package/msgerdefs/msgerdefs.d.ts +322 -0
- package/msgerdefs/msgerdefs.d.ts.map +1 -0
- package/msgerdefs/msgerdefs.js +110 -0
- package/msgerdefs/msgerdefs.js.map +1 -0
- package/msgerdefs/msgerdefs.ts +427 -0
- package/msgerdefs/package.json +38 -0
- package/msgerdefs/samples.html +431 -0
- package/msgerdefs/test1.cmd +1 -0
- package/msgerdefs/tsconfig.json +17 -0
- package/msgernative-linux-x64 +0 -0
- package/package.json +5 -1
- package/shower.d.ts +2 -0
- package/shower.d.ts.map +1 -1
- package/shower.js +17 -0
- package/shower.js.map +1 -1
- package/shower.ts +24 -0
- package/test-data-persistence.html +315 -0
- package/test-htmlfrom.html +29 -0
- package/test-ipc-reach.html +113 -0
- package/test-msger-api.html +120 -0
- package/test-msger-functions.html +325 -0
- package/msger-native/bin/msgernative.exe.WebView2/EBWebView/BrowserMetrics/BrowserMetrics-69055419-C8A0.pma +0 -0
package/msger-native/src/main.rs
CHANGED
|
@@ -1,11 +1,100 @@
|
|
|
1
1
|
use serde::{Deserialize, Serialize};
|
|
2
2
|
use std::io::{self, Read};
|
|
3
3
|
use tao::{
|
|
4
|
-
event::{Event, WindowEvent},
|
|
4
|
+
event::{Event, WindowEvent, ElementState, KeyEvent},
|
|
5
5
|
event_loop::{ControlFlow, EventLoop},
|
|
6
|
+
keyboard::KeyCode,
|
|
6
7
|
window::WindowBuilder,
|
|
7
8
|
};
|
|
8
|
-
use wry::WebViewBuilder;
|
|
9
|
+
use wry::{WebViewBuilder, WebContext};
|
|
10
|
+
|
|
11
|
+
// JavaScript API to inject into webviews
|
|
12
|
+
const MSGER_JS_API: &str = r#"
|
|
13
|
+
(function() {
|
|
14
|
+
console.log('[MSGER] Initializing msger API...');
|
|
15
|
+
|
|
16
|
+
// Check if IPC is available
|
|
17
|
+
const hasIPC = typeof window.ipc !== 'undefined' && window.ipc.postMessage;
|
|
18
|
+
console.log('[MSGER] IPC available:', hasIPC);
|
|
19
|
+
|
|
20
|
+
// Helper to safely send IPC messages
|
|
21
|
+
function safePostMessage(data) {
|
|
22
|
+
try {
|
|
23
|
+
if (!hasIPC) {
|
|
24
|
+
console.error('msger API: window.ipc not available');
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
window.ipc.postMessage(JSON.stringify(data));
|
|
28
|
+
return true;
|
|
29
|
+
} catch(e) {
|
|
30
|
+
console.error('msger API error:', e);
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
window.msger = {
|
|
36
|
+
// Window control - only close() with window.close() workaround (IPC broken)
|
|
37
|
+
close: function(result) {
|
|
38
|
+
// IPC is broken in wry 0.47.2, so we use window.close() instead
|
|
39
|
+
// Result cannot be returned to parent process
|
|
40
|
+
try {
|
|
41
|
+
window.close();
|
|
42
|
+
return true;
|
|
43
|
+
} catch(e) {
|
|
44
|
+
console.error('window.close() failed:', e);
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
saveData: function(key, value) {
|
|
49
|
+
try {
|
|
50
|
+
localStorage.setItem('msger_' + key, JSON.stringify(value));
|
|
51
|
+
return true;
|
|
52
|
+
} catch(e) {
|
|
53
|
+
console.error('Failed to save data:', e);
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
loadData: function(key, defaultValue) {
|
|
58
|
+
try {
|
|
59
|
+
const item = localStorage.getItem('msger_' + key);
|
|
60
|
+
return item ? JSON.parse(item) : defaultValue;
|
|
61
|
+
} catch(e) {
|
|
62
|
+
console.error('Failed to load data:', e);
|
|
63
|
+
return defaultValue;
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
removeData: function(key) {
|
|
67
|
+
try {
|
|
68
|
+
localStorage.removeItem('msger_' + key);
|
|
69
|
+
return true;
|
|
70
|
+
} catch(e) {
|
|
71
|
+
console.error('Failed to remove data:', e);
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
clearData: function() {
|
|
76
|
+
try {
|
|
77
|
+
const keys = Object.keys(localStorage);
|
|
78
|
+
for (const key of keys) {
|
|
79
|
+
if (key.startsWith('msger_')) {
|
|
80
|
+
localStorage.removeItem(key);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return true;
|
|
84
|
+
} catch(e) {
|
|
85
|
+
console.error('Failed to clear data:', e);
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
// Check if running in msger environment
|
|
90
|
+
isAvailable: function() {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
console.log('[MSGER] API initialized successfully! window.msger =', window.msger);
|
|
96
|
+
})();
|
|
97
|
+
"#;
|
|
9
98
|
|
|
10
99
|
#[derive(Deserialize, Debug)]
|
|
11
100
|
#[serde(rename_all = "camelCase")]
|
|
@@ -54,6 +143,10 @@ struct MessageBoxOptions {
|
|
|
54
143
|
zoom_percent: Option<f64>,
|
|
55
144
|
#[serde(default)]
|
|
56
145
|
debug: bool,
|
|
146
|
+
#[serde(default)]
|
|
147
|
+
icon: Option<String>,
|
|
148
|
+
#[serde(default)]
|
|
149
|
+
dev: bool,
|
|
57
150
|
}
|
|
58
151
|
|
|
59
152
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
@@ -98,6 +191,29 @@ fn default_buttons() -> Vec<String> {
|
|
|
98
191
|
vec!["OK".to_string()]
|
|
99
192
|
}
|
|
100
193
|
|
|
194
|
+
fn load_icon(icon_path: &str) -> Option<tao::window::Icon> {
|
|
195
|
+
use image::GenericImageView;
|
|
196
|
+
|
|
197
|
+
match image::open(icon_path) {
|
|
198
|
+
Ok(img) => {
|
|
199
|
+
let (width, height) = img.dimensions();
|
|
200
|
+
let rgba = img.to_rgba8().into_raw();
|
|
201
|
+
|
|
202
|
+
match tao::window::Icon::from_rgba(rgba, width, height) {
|
|
203
|
+
Ok(icon) => Some(icon),
|
|
204
|
+
Err(e) => {
|
|
205
|
+
eprintln!("Failed to create icon from {}: {}", icon_path, e);
|
|
206
|
+
None
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
Err(e) => {
|
|
211
|
+
eprintln!("Failed to load icon {}: {}", icon_path, e);
|
|
212
|
+
None
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
101
217
|
fn generate_html(options: &MessageBoxOptions) -> String {
|
|
102
218
|
let html_content = if let Some(ref html) = options.html {
|
|
103
219
|
html.clone()
|
|
@@ -148,10 +264,11 @@ fn generate_html(options: &MessageBoxOptions) -> String {
|
|
|
148
264
|
.replace("{INPUT}", &input_html)
|
|
149
265
|
.replace("{BUTTONS}", &buttons_html)
|
|
150
266
|
.replace("{AUTO_SIZE}", if options.auto_size { "true" } else { "false" })
|
|
267
|
+
.replace("{FULLSCREEN}", if options.fullscreen { "true" } else { "false" })
|
|
151
268
|
.replace("{ZOOM_PERCENT}", &options.zoom_percent.unwrap_or(100.0).to_string())
|
|
152
269
|
.replace("{DEFAULT_BUTTON}", options.buttons.first().unwrap_or(&"Cancel".to_string()))
|
|
153
270
|
.replace("{TIMEOUT_SECONDS}", &options.timeout.map(|t| t.to_string()).unwrap_or_else(|| "0".to_string()));
|
|
154
|
-
|
|
271
|
+
|
|
155
272
|
html
|
|
156
273
|
}
|
|
157
274
|
|
|
@@ -178,32 +295,41 @@ fn main() {
|
|
|
178
295
|
|
|
179
296
|
// Calculate position with optional screen offset (Windows only)
|
|
180
297
|
let final_position = if let Some(ref pos) = options.pos {
|
|
181
|
-
#[cfg(target_os = "windows")]
|
|
182
298
|
let mut x = pos.x;
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
// On Windows, calculate screen offset if screen number provided
|
|
299
|
+
let mut y = pos.y;
|
|
300
|
+
|
|
301
|
+
// On Windows, get the actual monitor position if screen number provided
|
|
188
302
|
#[cfg(target_os = "windows")]
|
|
189
303
|
if let Some(screen_num) = pos.screen {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
304
|
+
// Get all monitors
|
|
305
|
+
let monitors: Vec<_> = event_loop.available_monitors().collect();
|
|
306
|
+
|
|
307
|
+
// Get the specific monitor by index
|
|
308
|
+
if let Some(monitor) = monitors.get(screen_num as usize) {
|
|
309
|
+
// Get the monitor's actual position from the OS
|
|
310
|
+
let monitor_pos = monitor.position();
|
|
311
|
+
|
|
312
|
+
// Add user's offset to monitor's position
|
|
313
|
+
x += monitor_pos.x;
|
|
314
|
+
y += monitor_pos.y;
|
|
315
|
+
} else {
|
|
316
|
+
eprintln!("Warning: Screen {} not found, using primary monitor", screen_num);
|
|
199
317
|
}
|
|
200
318
|
}
|
|
201
|
-
|
|
319
|
+
|
|
202
320
|
Some(tao::dpi::LogicalPosition::new(x as f64, y as f64))
|
|
203
321
|
} else {
|
|
204
322
|
None
|
|
205
323
|
};
|
|
206
|
-
|
|
324
|
+
|
|
325
|
+
// Load window icon (default or custom)
|
|
326
|
+
let icon = if let Some(ref icon_path) = options.icon {
|
|
327
|
+
load_icon(icon_path)
|
|
328
|
+
} else {
|
|
329
|
+
// Try default icon.png in current directory
|
|
330
|
+
load_icon("icon.png")
|
|
331
|
+
};
|
|
332
|
+
|
|
207
333
|
let mut window_builder = WindowBuilder::new()
|
|
208
334
|
.with_title(&options.title)
|
|
209
335
|
.with_inner_size(tao::dpi::LogicalSize::new(
|
|
@@ -213,6 +339,11 @@ fn main() {
|
|
|
213
339
|
.with_resizable(true)
|
|
214
340
|
.with_always_on_top(options.always_on_top);
|
|
215
341
|
|
|
342
|
+
// Set icon if loaded successfully
|
|
343
|
+
if let Some(icon) = icon {
|
|
344
|
+
window_builder = window_builder.with_window_icon(Some(icon));
|
|
345
|
+
}
|
|
346
|
+
|
|
216
347
|
// Set fullscreen mode if requested
|
|
217
348
|
if options.fullscreen {
|
|
218
349
|
window_builder = window_builder.with_fullscreen(Some(tao::window::Fullscreen::Borderless(None)));
|
|
@@ -222,9 +353,9 @@ fn main() {
|
|
|
222
353
|
window_builder = window_builder.with_position(position);
|
|
223
354
|
}
|
|
224
355
|
|
|
225
|
-
let window = window_builder
|
|
356
|
+
let window = std::sync::Arc::new(window_builder
|
|
226
357
|
.build(&event_loop)
|
|
227
|
-
.expect("Failed to create window");
|
|
358
|
+
.expect("Failed to create window"));
|
|
228
359
|
|
|
229
360
|
// Generate HTML
|
|
230
361
|
let html = generate_html(&options);
|
|
@@ -248,6 +379,14 @@ fn main() {
|
|
|
248
379
|
let debug_info_clone = debug_info.clone();
|
|
249
380
|
let debug_info_clone2 = debug_info.clone();
|
|
250
381
|
|
|
382
|
+
// Create action holder for window operations from JavaScript
|
|
383
|
+
let pending_action = std::sync::Arc::new(std::sync::Mutex::new(None::<serde_json::Value>));
|
|
384
|
+
let pending_action_clone = pending_action.clone();
|
|
385
|
+
let pending_action_clone2 = pending_action.clone();
|
|
386
|
+
|
|
387
|
+
// Clone window for event loop
|
|
388
|
+
let window_clone = window.clone();
|
|
389
|
+
|
|
251
390
|
// Set up timeout if specified
|
|
252
391
|
let timeout_instant = options.timeout.map(|secs| {
|
|
253
392
|
std::time::Instant::now() + std::time::Duration::from_secs(secs)
|
|
@@ -256,22 +395,42 @@ fn main() {
|
|
|
256
395
|
let timeout_debug = debug_info.clone();
|
|
257
396
|
let timeout_buttons = options.buttons.clone();
|
|
258
397
|
|
|
398
|
+
// Create WebContext with custom user data directory for msger (separate from other WebView2 apps)
|
|
399
|
+
let data_directory = if let Some(local_app_data) = std::env::var_os("LOCALAPPDATA") {
|
|
400
|
+
let mut path = std::path::PathBuf::from(local_app_data);
|
|
401
|
+
path.push("msger");
|
|
402
|
+
path.push("webview2");
|
|
403
|
+
Some(path)
|
|
404
|
+
} else {
|
|
405
|
+
None
|
|
406
|
+
};
|
|
407
|
+
let mut web_context = WebContext::new(data_directory);
|
|
408
|
+
|
|
259
409
|
// Create webview with IPC handler
|
|
260
|
-
let
|
|
261
|
-
// Load URL
|
|
262
|
-
WebViewBuilder::
|
|
410
|
+
let mut webview = if let Some(ref url) = options.url {
|
|
411
|
+
// Load URL with msger API injected
|
|
412
|
+
WebViewBuilder::with_web_context(&mut web_context)
|
|
263
413
|
.with_url(url)
|
|
414
|
+
.with_initialization_script(MSGER_JS_API)
|
|
264
415
|
.with_devtools(true)
|
|
265
416
|
.with_ipc_handler(move |msg| {
|
|
266
|
-
//
|
|
267
|
-
if let Ok(
|
|
268
|
-
|
|
417
|
+
// Parse message as JSON
|
|
418
|
+
if let Ok(json_msg) = serde_json::from_str::<serde_json::Value>(msg.body()) {
|
|
419
|
+
// Check for action messages
|
|
420
|
+
if json_msg.get("_action").is_some() {
|
|
421
|
+
let mut action_lock = pending_action_clone.lock().unwrap();
|
|
422
|
+
*action_lock = Some(json_msg);
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Check for resize message
|
|
427
|
+
if json_msg.get("_resize").and_then(|v| v.as_bool()).unwrap_or(false) {
|
|
269
428
|
// This is a resize message - we'll handle it in the event loop
|
|
270
429
|
// For now, just ignore it (window resize from IPC is complex in wry/tao)
|
|
271
430
|
return;
|
|
272
431
|
}
|
|
273
432
|
}
|
|
274
|
-
|
|
433
|
+
|
|
275
434
|
// Parse the result from JavaScript (msg is now a Request<String>)
|
|
276
435
|
if let Ok(mut res) = serde_json::from_str::<MessageBoxResult>(msg.body()) {
|
|
277
436
|
// Add debug info if requested
|
|
@@ -280,23 +439,31 @@ fn main() {
|
|
|
280
439
|
*result_lock = Some(res);
|
|
281
440
|
}
|
|
282
441
|
})
|
|
283
|
-
.build(
|
|
442
|
+
.build(window.as_ref())
|
|
284
443
|
.expect("Failed to create webview")
|
|
285
444
|
} else {
|
|
286
|
-
// Use HTML content
|
|
287
|
-
WebViewBuilder::
|
|
445
|
+
// Use HTML content (msger API already in template.html)
|
|
446
|
+
WebViewBuilder::with_web_context(&mut web_context)
|
|
288
447
|
.with_html(&html)
|
|
289
448
|
.with_devtools(true)
|
|
290
449
|
.with_ipc_handler(move |msg| {
|
|
291
|
-
//
|
|
292
|
-
if let Ok(
|
|
293
|
-
|
|
450
|
+
// Parse message as JSON
|
|
451
|
+
if let Ok(json_msg) = serde_json::from_str::<serde_json::Value>(msg.body()) {
|
|
452
|
+
// Check for action messages
|
|
453
|
+
if json_msg.get("_action").is_some() {
|
|
454
|
+
let mut action_lock = pending_action_clone2.lock().unwrap();
|
|
455
|
+
*action_lock = Some(json_msg);
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Check for resize message
|
|
460
|
+
if json_msg.get("_resize").and_then(|v| v.as_bool()).unwrap_or(false) {
|
|
294
461
|
// This is a resize message - we'll handle it in the event loop
|
|
295
462
|
// For now, just ignore it (window resize from IPC is complex in wry/tao)
|
|
296
463
|
return;
|
|
297
464
|
}
|
|
298
465
|
}
|
|
299
|
-
|
|
466
|
+
|
|
300
467
|
// Parse the result from JavaScript (msg is now a Request<String>)
|
|
301
468
|
if let Ok(mut res) = serde_json::from_str::<MessageBoxResult>(msg.body()) {
|
|
302
469
|
// Add debug info if requested
|
|
@@ -305,10 +472,18 @@ fn main() {
|
|
|
305
472
|
*result_lock = Some(res);
|
|
306
473
|
}
|
|
307
474
|
})
|
|
308
|
-
.build(
|
|
475
|
+
.build(window.as_ref())
|
|
309
476
|
.expect("Failed to create webview")
|
|
310
477
|
};
|
|
311
478
|
|
|
479
|
+
// Open DevTools if -dev flag was specified
|
|
480
|
+
if options.dev {
|
|
481
|
+
// TODO: open_devtools() method not available in wry 0.47.2
|
|
482
|
+
// webview.open_devtools();
|
|
483
|
+
eprintln!("Warning: -dev flag specified but open_devtools() not available in wry 0.47.2");
|
|
484
|
+
eprintln!("DevTools are enabled - press F12 to open manually");
|
|
485
|
+
}
|
|
486
|
+
|
|
312
487
|
// Run event loop
|
|
313
488
|
event_loop.run(move |event, _,control_flow| {
|
|
314
489
|
// Check timeout
|
|
@@ -335,6 +510,56 @@ fn main() {
|
|
|
335
510
|
}
|
|
336
511
|
|
|
337
512
|
match event {
|
|
513
|
+
Event::WindowEvent {
|
|
514
|
+
event: WindowEvent::KeyboardInput {
|
|
515
|
+
event: KeyEvent {
|
|
516
|
+
physical_key: key_code,
|
|
517
|
+
state: ElementState::Pressed,
|
|
518
|
+
..
|
|
519
|
+
},
|
|
520
|
+
..
|
|
521
|
+
},
|
|
522
|
+
..
|
|
523
|
+
} => {
|
|
524
|
+
match key_code {
|
|
525
|
+
// F11 toggles fullscreen
|
|
526
|
+
KeyCode::F11 => {
|
|
527
|
+
let is_fullscreen = window_clone.fullscreen().is_some();
|
|
528
|
+
if is_fullscreen {
|
|
529
|
+
window_clone.set_fullscreen(None);
|
|
530
|
+
} else {
|
|
531
|
+
// Get current monitor for fullscreen
|
|
532
|
+
let monitor = window_clone.current_monitor()
|
|
533
|
+
.or_else(|| window_clone.primary_monitor());
|
|
534
|
+
window_clone.set_fullscreen(Some(tao::window::Fullscreen::Borderless(monitor)));
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
// Escape exits fullscreen or dismisses window
|
|
538
|
+
KeyCode::Escape => {
|
|
539
|
+
let is_fullscreen = window_clone.fullscreen().is_some();
|
|
540
|
+
if is_fullscreen {
|
|
541
|
+
// Exit fullscreen
|
|
542
|
+
window_clone.set_fullscreen(None);
|
|
543
|
+
} else {
|
|
544
|
+
// Dismiss window
|
|
545
|
+
let mut result_lock = result.lock().unwrap();
|
|
546
|
+
if result_lock.is_none() {
|
|
547
|
+
*result_lock = Some(MessageBoxResult {
|
|
548
|
+
button: "Cancel".to_string(),
|
|
549
|
+
value: None,
|
|
550
|
+
form: None,
|
|
551
|
+
closed: None,
|
|
552
|
+
dismissed: Some(true),
|
|
553
|
+
timeout: None,
|
|
554
|
+
debug: debug_info.clone(),
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
*control_flow = ControlFlow::Exit;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
_ => {}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
338
563
|
Event::WindowEvent {
|
|
339
564
|
event: WindowEvent::CloseRequested,
|
|
340
565
|
..
|
|
@@ -355,6 +580,87 @@ fn main() {
|
|
|
355
580
|
*control_flow = ControlFlow::Exit;
|
|
356
581
|
}
|
|
357
582
|
Event::MainEventsCleared => {
|
|
583
|
+
// Process pending actions from JavaScript
|
|
584
|
+
let mut action_lock = pending_action.lock().unwrap();
|
|
585
|
+
if let Some(action_msg) = action_lock.take() {
|
|
586
|
+
if let Some(action) = action_msg.get("_action").and_then(|v| v.as_str()) {
|
|
587
|
+
eprintln!("DEBUG: Received IPC action: {}", action);
|
|
588
|
+
// Wrap all window operations in catch_unwind to prevent crashes
|
|
589
|
+
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
|
590
|
+
match action {
|
|
591
|
+
"toggleFullscreen" => {
|
|
592
|
+
let is_fullscreen = window_clone.fullscreen().is_some();
|
|
593
|
+
if is_fullscreen {
|
|
594
|
+
window_clone.set_fullscreen(None);
|
|
595
|
+
} else {
|
|
596
|
+
// Get current monitor for fullscreen
|
|
597
|
+
let monitor = window_clone.current_monitor()
|
|
598
|
+
.or_else(|| window_clone.primary_monitor());
|
|
599
|
+
window_clone.set_fullscreen(Some(tao::window::Fullscreen::Borderless(monitor)));
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
"setFullscreen" => {
|
|
603
|
+
if let Some(enabled) = action_msg.get("enabled").and_then(|v| v.as_bool()) {
|
|
604
|
+
if enabled {
|
|
605
|
+
// Get current monitor for fullscreen
|
|
606
|
+
let monitor = window_clone.current_monitor()
|
|
607
|
+
.or_else(|| window_clone.primary_monitor());
|
|
608
|
+
window_clone.set_fullscreen(Some(tao::window::Fullscreen::Borderless(monitor)));
|
|
609
|
+
} else {
|
|
610
|
+
window_clone.set_fullscreen(None);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
"minimize" => {
|
|
615
|
+
window_clone.set_minimized(true);
|
|
616
|
+
}
|
|
617
|
+
"maximize" => {
|
|
618
|
+
window_clone.set_maximized(!window_clone.is_maximized());
|
|
619
|
+
}
|
|
620
|
+
"setSize" => {
|
|
621
|
+
if let (Some(width), Some(height)) = (
|
|
622
|
+
action_msg.get("width").and_then(|v| v.as_f64()),
|
|
623
|
+
action_msg.get("height").and_then(|v| v.as_f64())
|
|
624
|
+
) {
|
|
625
|
+
window_clone.set_inner_size(tao::dpi::LogicalSize::new(width, height));
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
"setPosition" => {
|
|
629
|
+
if let (Some(x), Some(y)) = (
|
|
630
|
+
action_msg.get("x").and_then(|v| v.as_f64()),
|
|
631
|
+
action_msg.get("y").and_then(|v| v.as_f64())
|
|
632
|
+
) {
|
|
633
|
+
window_clone.set_outer_position(tao::dpi::LogicalPosition::new(x, y));
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
"setAlwaysOnTop" => {
|
|
637
|
+
if let Some(enabled) = action_msg.get("enabled").and_then(|v| v.as_bool()) {
|
|
638
|
+
window_clone.set_always_on_top(enabled);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
"setTitle" => {
|
|
642
|
+
if let Some(title) = action_msg.get("title").and_then(|v| v.as_str()) {
|
|
643
|
+
window_clone.set_title(title);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
"test" => {
|
|
647
|
+
eprintln!("DEBUG: Test IPC message received successfully!");
|
|
648
|
+
// Don't do anything, just testing if IPC works
|
|
649
|
+
}
|
|
650
|
+
_ => {
|
|
651
|
+
eprintln!("DEBUG: Unknown action: {}", action);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}));
|
|
655
|
+
|
|
656
|
+
// Log if operation failed
|
|
657
|
+
if let Err(e) = result {
|
|
658
|
+
eprintln!("Window operation '{}' panicked: {:?}", action, e);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
drop(action_lock);
|
|
663
|
+
|
|
358
664
|
// Check if result is set
|
|
359
665
|
let result_lock = result.lock().unwrap();
|
|
360
666
|
if result_lock.is_some() {
|