compactrs 2025.12.24

High-performance native Windows file compressor using WOF (Windows Overlay Filter)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
#![allow(unsafe_op_in_unsafe_fn)]
//! Theme provider module - Centralized theming resource management.
//!
//! This module owns all GDI resources (brushes, fonts) and handles safe interaction
//! with `uxtheme.dll` for advanced styling.

use std::sync::OnceLock;
use crate::types::*;
use crate::utils::to_wstring;
use crate::ui::state::AppTheme;

// ============================================================================
// Color Constants
// ============================================================================

pub const COLOR_DARK_BG: u32 = 0x001E1E1E; // Dark Gray
pub const COLOR_DARK_TEXT: u32 = 0x00FFFFFF; // White
pub const COLOR_LIGHT_BG: u32 = 0x00FFFFFF; // White
pub const COLOR_LIGHT_TEXT: u32 = 0x00000000; // Black

// List View Specifics
pub const COLOR_LIST_BG_DARK: u32 = 0x00202020;
pub const COLOR_LIST_TEXT_DARK: u32 = 0x00FFFFFF;
pub const COLOR_LIST_BG_LIGHT: u32 = 0x00FFFFFF;
pub const COLOR_LIST_TEXT_LIGHT: u32 = 0x00000000;

// Header Control
pub const COLOR_HEADER_TEXT_DARK: u32 = 0x00FFFFFF;

// ============================================================================
// Enums & Traits
// ============================================================================

/// Defines the type of control for theming purposes.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ControlType {
    Window,
    Button,
    AccentButton, // Windows 11 Fluent blue accent button
    List,
    CheckBox,
    ComboBox,
    Header,
    GroupBox,
    RadioButton, // New type for distinct styling
    ItemsView, // For specialized ListView themes
    Trackbar, 
    Edit,
    ProgressBar,
}

/// Trait for components that need to react to theme changes.
pub trait ThemeAware {
    fn on_theme_change(&mut self, is_dark: bool);
}

// ============================================================================
// Static Resources (Singleton & Global)
// ============================================================================

// Global Font Handle
static APP_FONT_HANDLE: OnceLock<isize> = OnceLock::new();

// Global Dark Background Brush
static DARK_BRUSH_HANDLE: OnceLock<isize> = OnceLock::new();

/// Structure to hold resolved Uxtheme function pointers.
struct UxthemeApi {
    allow_dark_mode: Option<extern "system" fn(HWND, bool) -> bool>,
    set_preferred_app_mode: Option<extern "system" fn(i32) -> i32>,
}

// Singleton for Uxtheme DLL loading
static UXTHEME_API: OnceLock<UxthemeApi> = OnceLock::new();

// ============================================================================
// Core Styling Functions
// ============================================================================

/// Applies the visual theme to a specific control or window.
pub unsafe fn apply_theme(hwnd: HWND, control_type: ControlType, is_dark: bool) {
    let (theme, sub_theme) = if is_dark {
        match control_type {
            ControlType::Window => ("DarkMode_Explorer", None),
            ControlType::Button => ("DarkMode_Explorer", None),
            ControlType::AccentButton => ("DarkMode_Explorer", None),
            ControlType::List => ("DarkMode_Explorer", None), 
            ControlType::CheckBox => ("DarkMode_Explorer", None),
            ControlType::ComboBox => ("DarkMode_CFD", None),
            ControlType::Header => ("DarkMode_ItemsView", None), 
            // GroupBox: native for readable text. 
            // RadioButton: Explorer for Blue Accent (text must be handled via separate label).
            ControlType::GroupBox => ("", None),
            ControlType::RadioButton => ("Explorer", None),
            ControlType::ItemsView => ("DarkMode_ItemsView", None),
            ControlType::Trackbar => ("", None), // Use default drawing but with dark background
            ControlType::Edit => ("DarkMode_Explorer", None),
            ControlType::ProgressBar => ("", None),
        }
    } else {
        match control_type {
            ControlType::Window => ("Explorer", None),
            ControlType::Button => ("Explorer", None),
            ControlType::AccentButton => ("Explorer", None),
            ControlType::List => ("Explorer", None),
            ControlType::CheckBox => ("Explorer", None),
            ControlType::ComboBox => ("Explorer", None),
            ControlType::Header => ("Explorer", None),
            ControlType::GroupBox => ("Explorer", None),
            ControlType::RadioButton => ("Explorer", None),
            ControlType::ItemsView => ("Explorer", None),
            ControlType::Trackbar => ("Explorer", None),
            ControlType::Edit => ("Explorer", None),
            ControlType::ProgressBar => ("Explorer", None),
        }
    };

    let theme_w = to_wstring(theme);
    let sub_theme_w = sub_theme.map(to_wstring); 
    
    let psz_sub_app_name = if let Some(ref s) = sub_theme_w {
        s.as_ptr()
    } else {
         // To disable visual styles, passing L"" as the second parameter is often required.
         if theme.is_empty() {
             theme_w.as_ptr()
         } else {
             std::ptr::null()
         }
    };
    
    // IMPORTANT: Allow Dark Mode *BEFORE* setting the theme.
    // This ensures that when SetWindowTheme triggers a resource load, it sees the dark mode flag.
    allow_dark_mode_for_window(hwnd, is_dark);
    
    SetWindowTheme(hwnd, theme_w.as_ptr(), psz_sub_app_name);

    if is_dark {
        // Force the control to update its theme data immediately
        SendMessageW(hwnd, WM_THEMECHANGED, 0, 0);
    }
}

/// Recursively applies theme to child controls.
pub unsafe fn apply_theme_recursive(parent: HWND, is_dark: bool) {
    let mut child = GetWindow(parent, GW_CHILD);
    while child != std::ptr::null_mut() {
        // Apply to child
        apply_theme_to_child(child, is_dark);
        
        // Recurse to children's children
        apply_theme_recursive(child, is_dark);
        
        child = GetWindow(child, GW_HWNDNEXT);
    }
}

unsafe fn apply_theme_to_child(hwnd: HWND, is_dark: bool) {
     let mut name_buf = [0u16; 256];
     let len = GetClassNameW(hwnd, name_buf.as_mut_ptr(), 256);
     let class_name = String::from_utf16_lossy(&name_buf[..len as usize]).to_lowercase();
     
     let ctype = if class_name == "button" {
         let style = GetWindowLongW(hwnd, GWL_STYLE) as u32;
         let bs_typ = style & 0xF; 
         if bs_typ == BS_GROUPBOX as u32 {
             ControlType::GroupBox
         } else if bs_typ == BS_CHECKBOX as u32 || bs_typ == BS_AUTOCHECKBOX as u32 || bs_typ == BS_3STATE as u32 || bs_typ == BS_AUTO3STATE as u32 {
             ControlType::CheckBox
         } else if bs_typ == BS_RADIOBUTTON as u32 || bs_typ == BS_AUTORADIOBUTTON as u32 {
             ControlType::RadioButton
         } else {
             ControlType::Button
         }
     } else if class_name == "combobox" {
         ControlType::ComboBox
     } else if class_name == "syslistview32" {
         ControlType::List
     } else if class_name == "sysheader32" {
         ControlType::Header
     } else if class_name == "msctls_trackbar32" {
         ControlType::Trackbar
     } else if class_name == "edit" {
         ControlType::Edit
     } else if class_name == "msctls_progress32" {
         ControlType::ProgressBar
     } else {
         return; // Unknown or ignored
     };
     
     apply_theme(hwnd, ctype, is_dark);
}

/// Applies the application font to the specified window.
pub fn apply_font(hwnd: HWND) {
    let font = get_app_font();
    unsafe {
        SendMessageW(hwnd, WM_SETFONT, font as WPARAM, 1);
    }
}

/// Helper to get the global background brush.
pub fn get_background_brush(is_dark: bool) -> HBRUSH {
    if is_dark {
        get_dark_brush()
    } else {
        unsafe { GetStockObject(WHITE_BRUSH) }
    }
}

/// Enables Dark Mode for a specific window handle using undocumented API.
pub fn allow_dark_mode_for_window(hwnd: HWND, allow: bool) {
    let api = UXTHEME_API.get_or_init(|| init_uxtheme());
    if let Some(func) = api.allow_dark_mode {
        func(hwnd, allow);
    }
}

/// Sets the preferred app mode (Global dark mode setting).
pub fn set_preferred_app_mode(allow_dark: bool) {
    let api = UXTHEME_API.get_or_init(|| init_uxtheme());
    if let Some(func) = api.set_preferred_app_mode {
        // 2 = AllowDark, 0 = Default
        let mode = if allow_dark { 2 } else { 0 }; 
        func(mode);
    }
}

// ============================================================================
// Internal Initializers
// ============================================================================

/// Initialize Uxtheme hooks explicitly. Code can call this early to ensure hooks are ready.
pub fn init() {
    UXTHEME_API.get_or_init(|| init_uxtheme());
}

fn init_uxtheme() -> UxthemeApi {
    unsafe {
        let uxtheme_name = to_wstring("uxtheme.dll");
        let uxtheme = LoadLibraryW(uxtheme_name.as_ptr());
        
        if uxtheme == std::ptr::null_mut() {
            return UxthemeApi { allow_dark_mode: None, set_preferred_app_mode: None };
        }

        let allow_dark_mode = GetProcAddress(uxtheme, 133 as *const u8).map(|f| {
             std::mem::transmute(f)
        });

        let set_preferred_app_mode = GetProcAddress(uxtheme, 135 as *const u8).map(|f| {
             std::mem::transmute(f)
        });

        UxthemeApi {
            allow_dark_mode,
            set_preferred_app_mode,
        }
    }
}

pub fn get_app_font() -> HFONT {
    let handle = *APP_FONT_HANDLE.get_or_init(|| unsafe {
        let font_height = -12; // ~9pt
        let font_name = to_wstring("Segoe UI Variable Display");
        CreateFontW(
            font_height,
            0, 0, 0,
            FW_NORMAL as i32,
            0, 0, 0,
            DEFAULT_CHARSET as u32,
            OUT_DEFAULT_PRECIS as u32,
            CLIP_DEFAULT_PRECIS as u32,
            CLEARTYPE_QUALITY as u32,
            (DEFAULT_PITCH | FF_DONTCARE) as u32,
            font_name.as_ptr(),
        ) as isize
    });
    handle as HFONT
}

pub fn get_dark_brush() -> HBRUSH {
    let handle = *DARK_BRUSH_HANDLE.get_or_init(|| unsafe {
        CreateSolidBrush(COLOR_DARK_BG) as isize
    });
    handle as HBRUSH
}

// Global Icon Font Handle (Segoe Fluent Icons)
static ICON_FONT_HANDLE: OnceLock<isize> = OnceLock::new();

pub fn get_icon_font() -> HFONT {
    let handle = *ICON_FONT_HANDLE.get_or_init(|| unsafe {
        let font_height = -16; // Slightly larger for icons
        let font_name = to_wstring("Segoe Fluent Icons");
        CreateFontW(
            font_height,
            0, 0, 0,
            FW_NORMAL as i32,
            0, 0, 0,
            DEFAULT_CHARSET as u32,
            OUT_DEFAULT_PRECIS as u32,
            CLIP_DEFAULT_PRECIS as u32,
            CLEARTYPE_QUALITY as u32,
            (DEFAULT_PITCH | FF_DONTCARE) as u32,
            font_name.as_ptr(),
        ) as isize
    });
    handle as HFONT
}

// ============================================================================
// Message Handlers
// ============================================================================

pub unsafe fn handle_standard_colors(
    hwnd: HWND,
    msg: u32,
    wparam: WPARAM,
    is_dark: bool,
) -> Option<LRESULT> {
    match msg {
        WM_CTLCOLOREDIT => {
             let hdc = wparam as HDC;
             if is_dark {
                  SetTextColor(hdc, COLOR_DARK_TEXT);
                  SetBkColor(hdc, COLOR_DARK_BG); // Solid background for text
                  SetBkMode(hdc, OPAQUE as i32);  // Ensure solid background is used
                 Some(get_dark_brush() as LRESULT)
             } else {
                 SetTextColor(hdc, COLOR_LIGHT_TEXT);
                 SetBkMode(hdc, TRANSPARENT as i32);
                 Some(unsafe { GetStockObject(WHITE_BRUSH) } as LRESULT)
             }
        },
        WM_CTLCOLORSTATIC | WM_CTLCOLORBTN | WM_CTLCOLORDLG => {
            let hdc = wparam as HDC;
            if is_dark {
                SetTextColor(hdc, COLOR_DARK_TEXT);
                SetBkMode(hdc, TRANSPARENT as i32);
                Some(get_dark_brush() as LRESULT)
            } else {
                SetTextColor(hdc, COLOR_LIGHT_TEXT);
                SetBkMode(hdc, TRANSPARENT as i32);
                Some(unsafe { GetStockObject(WHITE_BRUSH) } as LRESULT)
            }
        }
        WM_ERASEBKGND => {
            let brush = get_background_brush(is_dark);
            let hdc = wparam as HDC;
            let mut rc = unsafe { std::mem::zeroed() };
            GetClientRect(hwnd, &mut rc);
            FillRect(hdc, &rc, brush);
            Some(1)
        }
        _ => None,
    }
}

pub unsafe fn set_window_frame_theme(hwnd: HWND, is_dark: bool) {
    let dark_mode_val: i32 = if is_dark { 1 } else { 0 };
    
    // Dark Mode Frame (DWMWA_USE_IMMERSIVE_DARK_MODE = 20)
    let _ = DwmSetWindowAttribute(
        hwnd,
        DWMWA_USE_IMMERSIVE_DARK_MODE as u32,
        &dark_mode_val as *const _ as _,
        std::mem::size_of::<i32>() as u32,
    );

    // Mica Effect (Windows 11)
    let mica = 2; // DWM_SYSTEMBACKDROP_TYPE(2)
    let _ = DwmSetWindowAttribute(
        hwnd,
        DWMWA_SYSTEMBACKDROP_TYPE as u32,
        &mica as *const _ as _,
        std::mem::size_of::<i32>() as u32,
    );
}

// ============================================================================
// System Query Functions
// ============================================================================

pub unsafe fn is_system_dark_mode() -> bool {
    let subkey = to_wstring("Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize");
    let val_name = to_wstring("AppsUseLightTheme");
    let mut hkey: HKEY = std::ptr::null_mut();
    
    if RegOpenKeyExW(HKEY_CURRENT_USER, subkey.as_ptr(), 0, KEY_READ, &mut hkey) == 0 {
        let mut data: u32 = 0;
        let mut cb_data = std::mem::size_of::<u32>() as u32;
        let result = RegQueryValueExW(
            hkey,
            val_name.as_ptr(),
            std::ptr::null_mut(),
            std::ptr::null_mut(),
            &mut data as *mut _ as *mut u8,
            &mut cb_data,
        );
        RegCloseKey(hkey);
        
        if result == 0 {
            return data == 0; // 0 = dark mode, 1 = light mode
        }
    }
    false
}

pub unsafe fn is_app_dark_mode(hwnd: HWND) -> bool {
    use crate::ui::state::AppState;
    use crate::ui::framework::get_window_state;

    if let Some(st) = get_window_state::<AppState>(hwnd) {
        crate::ui::theme::resolve_mode(st.theme)
    } else {
        is_system_dark_mode()
    }
}

pub fn resolve_mode(theme: AppTheme) -> bool {
    match theme {
        AppTheme::Dark => true,
        AppTheme::Light => false,
        AppTheme::System => unsafe { is_system_dark_mode() },
    }
}