native_windows_gui2/win32/
mod.rs1pub(crate) mod base_helper;
2pub(crate) mod high_dpi;
3pub(crate) mod message_box;
4pub(crate) mod monitor;
5pub(crate) mod resources_helper;
6pub(crate) mod window;
7pub(crate) mod window_helper;
8
9#[cfg(feature = "menu")]
10pub(crate) mod menu;
11
12#[cfg(feature = "cursor")]
13pub(crate) mod cursor;
14
15#[cfg(feature = "clipboard")]
16pub(crate) mod clipboard;
17
18#[cfg(feature = "tabs")]
19pub(crate) mod tabs;
20
21#[cfg(feature = "extern-canvas")]
22pub(crate) mod extern_canvas;
23
24#[cfg(feature = "image-decoder")]
25pub(crate) mod image_decoder;
26
27#[cfg(feature = "rich-textbox")]
28pub(crate) mod richedit;
29
30#[cfg(feature = "plotting")]
31pub(crate) mod plotters_d2d;
32
33use crate::errors::NwgError;
34use std::{fs, mem, ptr};
35
36use winapi::um::winuser::{
37 DispatchMessageW, GA_ROOT, GetAncestor, IsDialogMessageW, TranslateMessage,
38};
39
40pub fn dispatch_thread_events() {
44 use winapi::um::winuser::GetMessageW;
45 use winapi::um::winuser::MSG;
46
47 unsafe {
48 let mut msg: MSG = mem::zeroed();
49 while GetMessageW(&mut msg, ptr::null_mut(), 0, 0) != 0 {
50 if IsDialogMessageW(GetAncestor(msg.hwnd, GA_ROOT), &mut msg) == 0 {
51 TranslateMessage(&msg);
52 DispatchMessageW(&msg);
53 }
54 }
55 }
56}
57
58pub fn dispatch_thread_events_with_callback<F>(mut cb: F)
63where
64 F: FnMut() -> () + 'static,
65{
66 use winapi::um::winuser::MSG;
67 use winapi::um::winuser::{PM_REMOVE, PeekMessageW, WM_QUIT};
68
69 unsafe {
70 let mut msg: MSG = mem::zeroed();
71 while msg.message != WM_QUIT {
72 let has_message = PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, PM_REMOVE) != 0;
73 if has_message {
74 if IsDialogMessageW(GetAncestor(msg.hwnd, GA_ROOT), &mut msg) == 0 {
75 TranslateMessage(&msg);
76 DispatchMessageW(&msg);
77 }
78 }
79
80 cb();
81 }
82 }
83}
84
85pub fn dispatch_thread_events_blocking_with_callback<F>(mut cb: F)
89where
90 F: FnMut() -> () + 'static,
91{
92 use winapi::um::winuser::GetMessageW;
93 use winapi::um::winuser::MSG;
94
95 unsafe {
96 let mut msg: MSG = mem::zeroed();
97 while GetMessageW(&mut msg, ptr::null_mut(), 0, 0) != 0 {
98 if IsDialogMessageW(GetAncestor(msg.hwnd, GA_ROOT), &mut msg) == 0 {
99 TranslateMessage(&msg);
100 DispatchMessageW(&msg);
101 }
102 cb();
103 }
104 }
105}
106
107pub fn stop_thread_dispatch() {
111 use winapi::um::winuser::PostMessageW;
112 use winapi::um::winuser::WM_QUIT;
113
114 unsafe { PostMessageW(ptr::null_mut(), WM_QUIT, 0, 0) };
115}
116
117pub fn enable_visual_styles() {
121 use winapi::shared::basetsd::ULONG_PTR;
122 use winapi::shared::minwindef::{DWORD, MAX_PATH, ULONG};
123 use winapi::um::fileapi::{GetTempFileNameW, GetTempPathW};
124 use winapi::um::winbase::{ACTCTXW, ActivateActCtx, CreateActCtxW};
125
126 const MANIFEST_CONTENT: &str = r#"
127<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
128<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
129 <description>native-windows-gui comctl32 manifest</description>
130 <dependency>
131 <dependentAssembly>
132 <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*" />
133 </dependentAssembly>
134 </dependency>
135</assembly>
136"#;
137 const ACTCTX_FLAG_SET_PROCESS_DEFAULT: DWORD = 0x010;
138
139 let mut tmp_dir = [0u16; MAX_PATH + 1];
140 if unsafe { GetTempPathW(tmp_dir.len() as u32, tmp_dir.as_mut_ptr()) } == 0 {
141 return;
142 }
143 let mut tmp_path = [0u16; MAX_PATH]; let prefix = ['n' as u16, 'w' as u16, 'g' as u16];
145 if unsafe { GetTempFileNameW(tmp_dir.as_ptr(), prefix.as_ptr(), 0, tmp_path.as_mut_ptr()) } == 0
146 {
147 return;
148 }
149
150 let manifest_path_raw = tmp_path;
151 let manifest_path = base_helper::from_utf16(&tmp_path);
152 let _ = fs::write(&manifest_path, MANIFEST_CONTENT);
153
154 let mut activation_cookie: ULONG_PTR = 0;
155 let mut act_ctx = ACTCTXW {
156 cbSize: mem::size_of::<ACTCTXW> as ULONG,
157 dwFlags: ACTCTX_FLAG_SET_PROCESS_DEFAULT,
158 lpSource: manifest_path_raw.as_ptr(),
159 wProcessorArchitecture: 0,
160 wLangId: 0,
161 lpAssemblyDirectory: ptr::null_mut(),
162 lpResourceName: ptr::null_mut(),
163 lpApplicationName: ptr::null_mut(),
164 hModule: ptr::null_mut(),
165 };
166
167 unsafe {
168 let handle = CreateActCtxW(&mut act_ctx);
169 ActivateActCtx(handle, &mut activation_cookie);
170 }
171
172 let _ = fs::remove_file(&manifest_path);
173}
174
175pub fn init_common_controls() -> Result<(), NwgError> {
180 use winapi::shared::winerror::{S_FALSE, S_OK};
181 use winapi::um::commctrl::{
182 ICC_BAR_CLASSES, ICC_DATE_CLASSES, ICC_LISTVIEW_CLASSES, ICC_PROGRESS_CLASS,
183 ICC_STANDARD_CLASSES, ICC_TAB_CLASSES, ICC_TREEVIEW_CLASSES,
184 };
185 use winapi::um::commctrl::{INITCOMMONCONTROLSEX, InitCommonControlsEx};
186 use winapi::um::libloaderapi::LoadLibraryW;
187 use winapi::um::objbase::CoInitialize;
188
189 unsafe {
190 let mut classes = ICC_BAR_CLASSES | ICC_STANDARD_CLASSES;
191
192 if cfg!(feature = "datetime-picker") {
193 classes |= ICC_DATE_CLASSES;
194 }
195
196 if cfg!(feature = "progress-bar") {
197 classes |= ICC_PROGRESS_CLASS;
198 }
199
200 if cfg!(feature = "tabs") {
201 classes |= ICC_TAB_CLASSES;
202 }
203
204 if cfg!(feature = "tree-view") {
205 classes |= ICC_TREEVIEW_CLASSES;
206 }
207
208 if cfg!(feature = "list-view") {
209 classes |= ICC_LISTVIEW_CLASSES;
210 }
211
212 if cfg!(feature = "rich-textbox") {
213 let lib = base_helper::to_utf16("Msftedit.dll");
214 LoadLibraryW(lib.as_ptr());
215 }
216
217 let data = INITCOMMONCONTROLSEX {
218 dwSize: mem::size_of::<INITCOMMONCONTROLSEX>() as u32,
219 dwICC: classes,
220 };
221
222 InitCommonControlsEx(&data);
223 }
224
225 window::init_window_class()?;
226 tabs_init()?;
227 extern_canvas_init()?;
228 frame_init()?;
229
230 match unsafe { CoInitialize(ptr::null_mut()) } {
231 S_OK | S_FALSE => Ok(()),
232 _ => Err(NwgError::initialization("CoInitialize failed")),
233 }
234}
235
236#[cfg(feature = "tabs")]
237fn tabs_init() -> Result<(), NwgError> {
238 tabs::create_tab_classes()
239}
240
241#[cfg(not(feature = "tabs"))]
242fn tabs_init() -> Result<(), NwgError> {
243 Ok(())
244}
245
246#[cfg(feature = "extern-canvas")]
247fn extern_canvas_init() -> Result<(), NwgError> {
248 extern_canvas::create_extern_canvas_classes()
249}
250
251#[cfg(not(feature = "extern-canvas"))]
252fn extern_canvas_init() -> Result<(), NwgError> {
253 Ok(())
254}
255
256#[cfg(feature = "frame")]
257fn frame_init() -> Result<(), NwgError> {
258 window::create_frame_classes()
259}
260
261#[cfg(not(feature = "frame"))]
262fn frame_init() -> Result<(), NwgError> {
263 Ok(())
264}