@bobfrankston/msger 0.1.149 → 0.1.151
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.
|
Binary file
|
|
Binary file
|
package/msger-native/src/main.rs
CHANGED
|
@@ -32,13 +32,33 @@ use windows::core::PCWSTR;
|
|
|
32
32
|
#[cfg(windows)]
|
|
33
33
|
use std::sync::atomic::{AtomicBool, Ordering};
|
|
34
34
|
|
|
35
|
-
// Custom menu
|
|
35
|
+
// Custom menu IDs (must be < 0xF000 to avoid conflicts with system commands)
|
|
36
36
|
#[cfg(windows)]
|
|
37
37
|
const IDM_ABOUT: u32 = 0x1000;
|
|
38
|
+
#[cfg(windows)]
|
|
39
|
+
const IDM_ZOOM_IN: u32 = 0x1001;
|
|
40
|
+
#[cfg(windows)]
|
|
41
|
+
const IDM_ZOOM_OUT: u32 = 0x1002;
|
|
42
|
+
#[cfg(windows)]
|
|
43
|
+
const IDM_ZOOM_RESET: u32 = 0x1003;
|
|
44
|
+
#[cfg(windows)]
|
|
45
|
+
const IDM_ZOOM_50: u32 = 0x1010;
|
|
46
|
+
#[cfg(windows)]
|
|
47
|
+
const IDM_ZOOM_75: u32 = 0x1011;
|
|
48
|
+
#[cfg(windows)]
|
|
49
|
+
const IDM_ZOOM_100: u32 = 0x1012;
|
|
50
|
+
#[cfg(windows)]
|
|
51
|
+
const IDM_ZOOM_125: u32 = 0x1013;
|
|
52
|
+
#[cfg(windows)]
|
|
53
|
+
const IDM_ZOOM_150: u32 = 0x1014;
|
|
54
|
+
#[cfg(windows)]
|
|
55
|
+
const IDM_ZOOM_200: u32 = 0x1015;
|
|
38
56
|
|
|
39
|
-
// Global
|
|
57
|
+
// Global flags
|
|
40
58
|
#[cfg(windows)]
|
|
41
59
|
static ABOUT_CLICKED: AtomicBool = AtomicBool::new(false);
|
|
60
|
+
#[cfg(windows)]
|
|
61
|
+
static ZOOM_ACTION: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0);
|
|
42
62
|
|
|
43
63
|
// Window subclass procedure to intercept WM_SYSCOMMAND
|
|
44
64
|
#[cfg(windows)]
|
|
@@ -52,10 +72,48 @@ unsafe extern "system" fn subclass_proc(
|
|
|
52
72
|
) -> LRESULT {
|
|
53
73
|
if msg == WM_SYSCOMMAND {
|
|
54
74
|
let cmd = wparam.0 & 0xFFF0;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
75
|
+
match cmd as u32 {
|
|
76
|
+
IDM_ABOUT => {
|
|
77
|
+
ABOUT_CLICKED.store(true, Ordering::SeqCst);
|
|
78
|
+
return LRESULT(0);
|
|
79
|
+
}
|
|
80
|
+
IDM_ZOOM_IN => {
|
|
81
|
+
ZOOM_ACTION.store(1, Ordering::SeqCst); // Zoom in
|
|
82
|
+
return LRESULT(0);
|
|
83
|
+
}
|
|
84
|
+
IDM_ZOOM_OUT => {
|
|
85
|
+
ZOOM_ACTION.store(2, Ordering::SeqCst); // Zoom out
|
|
86
|
+
return LRESULT(0);
|
|
87
|
+
}
|
|
88
|
+
IDM_ZOOM_RESET => {
|
|
89
|
+
ZOOM_ACTION.store(100, Ordering::SeqCst); // Reset to 100%
|
|
90
|
+
return LRESULT(0);
|
|
91
|
+
}
|
|
92
|
+
IDM_ZOOM_50 => {
|
|
93
|
+
ZOOM_ACTION.store(50, Ordering::SeqCst);
|
|
94
|
+
return LRESULT(0);
|
|
95
|
+
}
|
|
96
|
+
IDM_ZOOM_75 => {
|
|
97
|
+
ZOOM_ACTION.store(75, Ordering::SeqCst);
|
|
98
|
+
return LRESULT(0);
|
|
99
|
+
}
|
|
100
|
+
IDM_ZOOM_100 => {
|
|
101
|
+
ZOOM_ACTION.store(100, Ordering::SeqCst);
|
|
102
|
+
return LRESULT(0);
|
|
103
|
+
}
|
|
104
|
+
IDM_ZOOM_125 => {
|
|
105
|
+
ZOOM_ACTION.store(125, Ordering::SeqCst);
|
|
106
|
+
return LRESULT(0);
|
|
107
|
+
}
|
|
108
|
+
IDM_ZOOM_150 => {
|
|
109
|
+
ZOOM_ACTION.store(150, Ordering::SeqCst);
|
|
110
|
+
return LRESULT(0);
|
|
111
|
+
}
|
|
112
|
+
IDM_ZOOM_200 => {
|
|
113
|
+
ZOOM_ACTION.store(200, Ordering::SeqCst);
|
|
114
|
+
return LRESULT(0);
|
|
115
|
+
}
|
|
116
|
+
_ => {}
|
|
59
117
|
}
|
|
60
118
|
}
|
|
61
119
|
DefSubclassProc(hwnd, msg, wparam, lparam)
|
|
@@ -389,8 +447,22 @@ fn main() {
|
|
|
389
447
|
let icon = if let Some(ref icon_path) = options.icon {
|
|
390
448
|
load_icon(icon_path)
|
|
391
449
|
} else {
|
|
392
|
-
// Try default
|
|
393
|
-
|
|
450
|
+
// Try default msger.png next to the binary
|
|
451
|
+
if let Ok(exe_path) = std::env::current_exe() {
|
|
452
|
+
if let Some(exe_dir) = exe_path.parent() {
|
|
453
|
+
let default_icon = exe_dir.join("msger.png");
|
|
454
|
+
if default_icon.exists() {
|
|
455
|
+
load_icon(default_icon.to_str().unwrap_or("msger.png"))
|
|
456
|
+
} else {
|
|
457
|
+
// Fallback to msger.png in current directory
|
|
458
|
+
load_icon("msger.png")
|
|
459
|
+
}
|
|
460
|
+
} else {
|
|
461
|
+
load_icon("msger.png")
|
|
462
|
+
}
|
|
463
|
+
} else {
|
|
464
|
+
load_icon("msger.png")
|
|
465
|
+
}
|
|
394
466
|
};
|
|
395
467
|
|
|
396
468
|
let mut window_builder = WindowBuilder::new()
|
|
@@ -434,9 +506,45 @@ fn main() {
|
|
|
434
506
|
if !hmenu.is_invalid() {
|
|
435
507
|
// Add separator
|
|
436
508
|
AppendMenuW(hmenu, MF_SEPARATOR, 0, PCWSTR::null()).ok();
|
|
509
|
+
|
|
437
510
|
// Add About item
|
|
438
|
-
let about_text: Vec<u16> = "About (Window Info)\0".encode_utf16().collect();
|
|
511
|
+
let about_text: Vec<u16> = "About msger (Window Info)\0".encode_utf16().collect();
|
|
439
512
|
AppendMenuW(hmenu, MF_STRING, IDM_ABOUT as usize, PCWSTR(about_text.as_ptr())).ok();
|
|
513
|
+
|
|
514
|
+
// Add another separator
|
|
515
|
+
AppendMenuW(hmenu, MF_SEPARATOR, 0, PCWSTR::null()).ok();
|
|
516
|
+
|
|
517
|
+
// Add Zoom controls
|
|
518
|
+
let zoom_in: Vec<u16> = "Zoom In\tCtrl++\0".encode_utf16().collect();
|
|
519
|
+
AppendMenuW(hmenu, MF_STRING, IDM_ZOOM_IN as usize, PCWSTR(zoom_in.as_ptr())).ok();
|
|
520
|
+
|
|
521
|
+
let zoom_out: Vec<u16> = "Zoom Out\tCtrl+-\0".encode_utf16().collect();
|
|
522
|
+
AppendMenuW(hmenu, MF_STRING, IDM_ZOOM_OUT as usize, PCWSTR(zoom_out.as_ptr())).ok();
|
|
523
|
+
|
|
524
|
+
let zoom_reset: Vec<u16> = "Reset Zoom\tCtrl+0\0".encode_utf16().collect();
|
|
525
|
+
AppendMenuW(hmenu, MF_STRING, IDM_ZOOM_RESET as usize, PCWSTR(zoom_reset.as_ptr())).ok();
|
|
526
|
+
|
|
527
|
+
// Add separator before preset zooms
|
|
528
|
+
AppendMenuW(hmenu, MF_SEPARATOR, 0, PCWSTR::null()).ok();
|
|
529
|
+
|
|
530
|
+
// Add preset zoom levels
|
|
531
|
+
let zoom_50: Vec<u16> = "Zoom 50%\0".encode_utf16().collect();
|
|
532
|
+
AppendMenuW(hmenu, MF_STRING, IDM_ZOOM_50 as usize, PCWSTR(zoom_50.as_ptr())).ok();
|
|
533
|
+
|
|
534
|
+
let zoom_75: Vec<u16> = "Zoom 75%\0".encode_utf16().collect();
|
|
535
|
+
AppendMenuW(hmenu, MF_STRING, IDM_ZOOM_75 as usize, PCWSTR(zoom_75.as_ptr())).ok();
|
|
536
|
+
|
|
537
|
+
let zoom_100: Vec<u16> = "Zoom 100%\0".encode_utf16().collect();
|
|
538
|
+
AppendMenuW(hmenu, MF_STRING, IDM_ZOOM_100 as usize, PCWSTR(zoom_100.as_ptr())).ok();
|
|
539
|
+
|
|
540
|
+
let zoom_125: Vec<u16> = "Zoom 125%\0".encode_utf16().collect();
|
|
541
|
+
AppendMenuW(hmenu, MF_STRING, IDM_ZOOM_125 as usize, PCWSTR(zoom_125.as_ptr())).ok();
|
|
542
|
+
|
|
543
|
+
let zoom_150: Vec<u16> = "Zoom 150%\0".encode_utf16().collect();
|
|
544
|
+
AppendMenuW(hmenu, MF_STRING, IDM_ZOOM_150 as usize, PCWSTR(zoom_150.as_ptr())).ok();
|
|
545
|
+
|
|
546
|
+
let zoom_200: Vec<u16> = "Zoom 200%\0".encode_utf16().collect();
|
|
547
|
+
AppendMenuW(hmenu, MF_STRING, IDM_ZOOM_200 as usize, PCWSTR(zoom_200.as_ptr())).ok();
|
|
440
548
|
}
|
|
441
549
|
// Install window subclass to intercept WM_SYSCOMMAND
|
|
442
550
|
let _ = SetWindowSubclass(hwnd, Some(subclass_proc), 1, 0).ok();
|
|
@@ -696,6 +804,13 @@ fn main() {
|
|
|
696
804
|
// Check for About menu click
|
|
697
805
|
#[cfg(windows)]
|
|
698
806
|
if ABOUT_CLICKED.swap(false, Ordering::SeqCst) {
|
|
807
|
+
// Get current zoom from the page
|
|
808
|
+
let zoom_script = "document.body.style.zoom || '100%'";
|
|
809
|
+
let current_zoom = match webview.evaluate_script(zoom_script) {
|
|
810
|
+
Ok(_) => "100%".to_string(), // Default if can't get it
|
|
811
|
+
Err(_) => "100%".to_string(),
|
|
812
|
+
};
|
|
813
|
+
|
|
699
814
|
// Get window information
|
|
700
815
|
let position = window_clone.outer_position().unwrap_or_default();
|
|
701
816
|
let inner_size = window_clone.inner_size();
|
|
@@ -712,27 +827,29 @@ fn main() {
|
|
|
712
827
|
let logical_outer_height = (outer_size.height as f64 / scale_factor) as i32;
|
|
713
828
|
|
|
714
829
|
let info = format!(
|
|
715
|
-
"
|
|
716
|
-
|
|
830
|
+
"msger v{}\\n\\n\
|
|
831
|
+
Rust/wry-based message viewer\\n\\n\
|
|
832
|
+
Position: x={}, y={}\\n\
|
|
717
833
|
Logical Size (API): {}x{} inner\\n\
|
|
718
834
|
Physical Size (Screen): {}x{} inner\\n\
|
|
719
835
|
Outer Size (Physical): {}x{}\\n\
|
|
720
836
|
Outer Size (Logical): {}x{}\\n\\n\
|
|
837
|
+
Current Zoom: {}\\n\
|
|
721
838
|
Scale Factor: {:.2} ({}% DPI)\\n\
|
|
722
839
|
Maximized: {}\\n\
|
|
723
840
|
Fullscreen: {}\\n\
|
|
724
|
-
Always On Top: {}
|
|
725
|
-
|
|
841
|
+
Always On Top: {}",
|
|
842
|
+
get_package_version().unwrap_or_else(|| "unknown".to_string()),
|
|
726
843
|
position.x, position.y,
|
|
727
844
|
logical_inner_width, logical_inner_height,
|
|
728
845
|
inner_size.width, inner_size.height,
|
|
729
846
|
outer_size.width, outer_size.height,
|
|
730
847
|
logical_outer_width, logical_outer_height,
|
|
848
|
+
current_zoom,
|
|
731
849
|
scale_factor, (scale_factor * 100.0) as i32,
|
|
732
850
|
is_maximized,
|
|
733
851
|
is_fullscreen,
|
|
734
|
-
is_always_on_top
|
|
735
|
-
get_package_version().unwrap_or_else(|| "unknown".to_string())
|
|
852
|
+
is_always_on_top
|
|
736
853
|
);
|
|
737
854
|
|
|
738
855
|
// Show the info in an alert
|
|
@@ -742,6 +859,32 @@ fn main() {
|
|
|
742
859
|
}
|
|
743
860
|
}
|
|
744
861
|
|
|
862
|
+
// Check for zoom menu actions
|
|
863
|
+
#[cfg(windows)]
|
|
864
|
+
{
|
|
865
|
+
let zoom_action = ZOOM_ACTION.swap(0, Ordering::SeqCst);
|
|
866
|
+
if zoom_action != 0 {
|
|
867
|
+
let zoom_script = match zoom_action {
|
|
868
|
+
1 => {
|
|
869
|
+
// Zoom in - get current and increase by 25%
|
|
870
|
+
"var currentZoom = parseFloat(document.body.style.zoom || '100'); document.body.style.zoom = (currentZoom + 25) + '%';"
|
|
871
|
+
}
|
|
872
|
+
2 => {
|
|
873
|
+
// Zoom out - get current and decrease by 25%
|
|
874
|
+
"var currentZoom = parseFloat(document.body.style.zoom || '100'); document.body.style.zoom = Math.max(25, currentZoom - 25) + '%';"
|
|
875
|
+
}
|
|
876
|
+
percent => {
|
|
877
|
+
// Set specific zoom level
|
|
878
|
+
&format!("document.body.style.zoom = '{}%';", percent)
|
|
879
|
+
}
|
|
880
|
+
};
|
|
881
|
+
|
|
882
|
+
if let Err(e) = webview.evaluate_script(zoom_script) {
|
|
883
|
+
eprintln!("Failed to set zoom: {}", e);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
|
|
745
888
|
// Check timeout
|
|
746
889
|
if let Some(deadline) = timeout_instant {
|
|
747
890
|
if std::time::Instant::now() >= deadline {
|
package/msger.png
ADDED
|
Binary file
|