11use std:: fmt;
22
33use serde:: Deserialize ;
4- use windows:: {
5- core:: PCWSTR ,
6- Win32 :: {
7- Foundation :: { ERROR_SUCCESS , LPARAM , WPARAM } ,
8- System :: Registry :: {
9- RegCloseKey , RegOpenKeyExW , RegQueryValueExW , RegSetValueExW , HKEY , HKEY_CURRENT_USER ,
10- KEY_QUERY_VALUE , KEY_SET_VALUE , REG_DWORD , REG_SAM_FLAGS ,
11- } ,
12- UI :: WindowsAndMessaging :: { SendNotifyMessageW , HWND_BROADCAST , WM_SETTINGCHANGE } ,
13- } ,
4+ use windows:: Win32 :: {
5+ Foundation :: { LPARAM , WPARAM } ,
6+ System :: Registry :: { KEY_QUERY_VALUE , KEY_SET_VALUE , REG_DWORD } ,
7+ UI :: WindowsAndMessaging :: { SendNotifyMessageW , HWND_BROADCAST , WM_SETTINGCHANGE } ,
148} ;
159
16- use crate :: { error:: DwallResult , utils:: string:: WideStringExt } ;
17-
18- /// Custom error types for registry operations
19- #[ derive( thiserror:: Error , Debug ) ]
20- pub enum ColorModeRegistryError {
21- #[ error( "Registry operation failed: Open key {0}" ) ]
22- Open ( u32 ) ,
23-
24- #[ error( "Registry operation failed: Query value {0}" ) ]
25- Query ( u32 ) ,
26-
27- #[ error( "Registry operation failed: Set value {0}" ) ]
28- Set ( u32 ) ,
29-
30- #[ error( "Registry operation failed: Close key {0}" ) ]
31- Close ( u32 ) ,
32- }
10+ use crate :: { error:: DwallResult , registry:: RegistryKey , utils:: string:: WideStringExt } ;
3311
3412#[ derive( Debug , PartialEq , Deserialize ) ]
3513#[ serde( rename_all = "UPPERCASE" ) ]
@@ -38,78 +16,23 @@ pub enum ColorMode {
3816 Dark ,
3917}
4018
41- impl fmt :: Display for ColorMode {
42- fn fmt ( & self , f : & mut fmt :: Formatter < ' _ > ) -> fmt :: Result {
19+ impl ColorMode {
20+ fn as_u32 ( & self ) -> u32 {
4321 match self {
44- ColorMode :: Light => write ! ( f, "Light" ) ,
45- ColorMode :: Dark => write ! ( f, "Dark" ) ,
46- }
47- }
48- }
49-
50- /// RAII wrapper for Windows registry key handles
51- /// Automatically closes the key handle when dropped
52- struct RegistryKey {
53- hkey : HKEY ,
54- path : String ,
55- }
56-
57- impl RegistryKey {
58- /// Open a registry key with specified access rights
59- fn open ( path : & str , access : REG_SAM_FLAGS ) -> DwallResult < Self > {
60- debug ! ( path = path, "Attempting to open registry key" ) ;
61- let wide_path = Vec :: from_str ( path) ;
62- let mut hkey = HKEY :: default ( ) ;
63-
64- unsafe {
65- let result = RegOpenKeyExW (
66- HKEY_CURRENT_USER ,
67- PCWSTR ( wide_path. as_ptr ( ) ) ,
68- None ,
69- access,
70- & mut hkey,
71- ) ;
72-
73- match result {
74- ERROR_SUCCESS => {
75- info ! ( path = path, "Successfully opened registry key" ) ;
76- Ok ( Self {
77- hkey,
78- path : path. to_string ( ) ,
79- } )
80- }
81- err => {
82- error ! (
83- path = path,
84- error_code = err. 0 ,
85- "Failed to open registry key"
86- ) ;
87- Err ( ColorModeRegistryError :: Open ( err. 0 ) . into ( ) )
88- }
89- }
22+ ColorMode :: Light => 1 ,
23+ ColorMode :: Dark => 0 ,
9024 }
9125 }
92-
93- /// Get the raw HKEY handle
94- fn as_raw ( & self ) -> HKEY {
95- self . hkey
26+ fn to_le_bytes ( & self ) -> [ u8 ; 4 ] {
27+ self . as_u32 ( ) . to_le_bytes ( )
9628 }
9729}
9830
99- impl Drop for RegistryKey {
100- fn drop ( & mut self ) {
101- trace ! ( path = self . path, "Automatically closing registry key" ) ;
102- unsafe {
103- let err = RegCloseKey ( self . hkey ) ;
104- if err != ERROR_SUCCESS {
105- warn ! (
106- path = self . path,
107- error_code = err. 0 ,
108- "Failed to close registry key on drop"
109- ) ;
110- } else {
111- debug ! ( path = self . path, "Successfully closed registry key" ) ;
112- }
31+ impl fmt:: Display for ColorMode {
32+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
33+ match self {
34+ ColorMode :: Light => write ! ( f, "Light" ) ,
35+ ColorMode :: Dark => write ! ( f, "Dark" ) ,
11336 }
11437 }
11538}
@@ -132,41 +55,26 @@ impl ColorModeManager {
13255 info ! ( "Retrieving current system color mode" ) ;
13356 let registry_key = RegistryKey :: open ( Self :: PERSONALIZE_KEY_PATH , KEY_QUERY_VALUE ) ?;
13457
135- let value_name = Vec :: from_str ( Self :: APPS_THEME_VALUE ) ;
136- let mut value: u32 = 0 ;
137- let mut size = std:: mem:: size_of :: < u32 > ( ) as u32 ;
138-
139- unsafe {
140- let result = RegQueryValueExW (
141- registry_key. as_raw ( ) ,
142- PCWSTR ( value_name. as_ptr ( ) ) ,
143- None ,
144- None ,
145- Some ( & mut value as * mut u32 as * mut u8 ) ,
146- Some ( & mut size) ,
147- ) ;
148-
149- match result {
150- ERROR_SUCCESS => {
151- let mode = if value == 1 {
152- debug ! ( "Current color mode is Light" ) ;
153- ColorMode :: Light
154- } else {
155- debug ! ( "Current color mode is Dark" ) ;
156- ColorMode :: Dark
157- } ;
158- Ok ( mode)
159- }
160- err => {
161- error ! (
162- value_name = Self :: APPS_THEME_VALUE ,
163- error_code = err. 0 ,
164- "Failed to query color mode value"
165- ) ;
166- Err ( ColorModeRegistryError :: Query ( err. 0 ) . into ( ) )
167- }
168- }
169- }
58+ let mut data: u32 = 0 ;
59+ let mut data_size = std:: mem:: size_of_val ( & data) as u32 ;
60+ let mut data_type = REG_DWORD ;
61+
62+ registry_key. query (
63+ Self :: APPS_THEME_VALUE ,
64+ Some ( std:: ptr:: addr_of_mut!( data_type) ) ,
65+ Some ( std:: ptr:: addr_of_mut!( data) as * mut u8 ) ,
66+ Some ( & mut data_size) ,
67+ ) ?;
68+ debug ! ( value = data, "Retrieved app theme value from registry" ) ;
69+
70+ let mode = if data == 1 {
71+ debug ! ( "Current color mode is Light" ) ;
72+ ColorMode :: Light
73+ } else {
74+ debug ! ( "Current color mode is Dark" ) ;
75+ ColorMode :: Dark
76+ } ;
77+ Ok ( mode)
17078 }
17179
17280 /// Set the system color mode in the registry
@@ -181,51 +89,25 @@ impl ColorModeManager {
18189 info ! ( mode = %mode, "Setting system color mode" ) ;
18290 let registry_key = RegistryKey :: open ( Self :: PERSONALIZE_KEY_PATH , KEY_SET_VALUE ) ?;
18391
184- let value = match mode {
185- ColorMode :: Light => [ 1u8 , 0 , 0 , 0 ] ,
186- ColorMode :: Dark => [ 0u8 , 0 , 0 , 0 ] ,
187- } ;
188-
189- let apps_value = Vec :: from_str ( Self :: APPS_THEME_VALUE ) ;
190- let system_value = Vec :: from_str ( Self :: SYSTEM_THEME_VALUE ) ;
191-
192- unsafe {
193- let set_apps_result = RegSetValueExW (
194- registry_key. as_raw ( ) ,
195- PCWSTR ( apps_value. as_ptr ( ) ) ,
196- None ,
197- REG_DWORD ,
198- Some ( & value) ,
199- ) ;
200-
201- let set_system_result = RegSetValueExW (
202- registry_key. as_raw ( ) ,
203- PCWSTR ( system_value. as_ptr ( ) ) ,
204- None ,
205- REG_DWORD ,
206- Some ( & value) ,
207- ) ;
208-
209- match ( set_apps_result, set_system_result) {
210- ( ERROR_SUCCESS , ERROR_SUCCESS ) => {
211- info ! ( mode = %mode, "Successfully set color mode" ) ;
212- }
213- _ => {
214- error ! (
215- mode = %mode,
216- apps_result = set_apps_result. 0 ,
217- system_result = set_system_result. 0 ,
218- "Failed to set color mode"
219- ) ;
220- return Err ( ColorModeRegistryError :: Set (
221- set_apps_result. 0 | set_system_result. 0 ,
222- )
223- . into ( ) ) ;
224- }
225- } ;
226-
227- notify_theme_change ( ) ?;
228- }
92+ let value = mode. to_le_bytes ( ) ;
93+
94+ registry_key
95+ . set ( Self :: APPS_THEME_VALUE , REG_DWORD , & value)
96+ . map_err ( |e| {
97+ error ! ( error =?e, "Failed to set apps theme value" ) ;
98+ e
99+ } ) ?;
100+ info ! ( mode = %mode, "Successfully set apps theme value" ) ;
101+
102+ registry_key
103+ . set ( Self :: SYSTEM_THEME_VALUE , REG_DWORD , & value)
104+ . map_err ( |e| {
105+ error ! ( error =?e, "Failed to set system theme value" ) ;
106+ e
107+ } ) ?;
108+ info ! ( mode = %mode, "Successfully set system theme value" ) ;
109+
110+ notify_theme_change ( ) ?;
229111
230112 Ok ( ( ) )
231113 }
0 commit comments