Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support light/dark theme and adherence to system theme #140

Merged
merged 1 commit into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 39 additions & 7 deletions src/painter.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::app::SwitchAppsState;
use crate::utils::RegKey;
use anyhow::Result;
use windows::core::w;
use windows::Win32::Foundation::{COLORREF, RECT};
use windows::Win32::Graphics::Gdi::{
BeginPaint, BitBlt, CreateCompatibleBitmap, CreateCompatibleDC, CreateSolidBrush, DeleteDC,
Expand All @@ -8,10 +11,14 @@ use windows::Win32::Graphics::Gdi::{
use windows::Win32::UI::WindowsAndMessaging::{DrawIconEx, DI_NORMAL};
use windows::Win32::{Foundation::HWND, Graphics::Gdi::GetDC};

// window background color
pub const BG_COLOR: COLORREF = COLORREF(0x3b3b3b);
// selected icon box color
pub const FG_COLOR: COLORREF = COLORREF(0x4c4c4c);
// window background color in dark theme
pub const BG_DARK_COLOR: COLORREF = COLORREF(0x3b3b3b);
// selected icon box color in dark theme
pub const FG_DARK_COLOR: COLORREF = COLORREF(0x4c4c4c);
// window background color in light theme
pub const BG_LIGHT_COLOR: COLORREF = COLORREF(0xf2f2f2);
// selected icon box color in light theme
pub const FG_LIGHT_COLOR: COLORREF = COLORREF(0xe0e0e0);
// minimum icon size
pub const ICON_SIZE: i32 = 64;
// window padding
Expand All @@ -35,13 +42,27 @@ pub struct GdiAAPainter {
size: i32,
// scale
scale: i32,
// color
fg_color: COLORREF,
bg_color: COLORREF,
}

impl GdiAAPainter {
/// Creates a new [GdiAAPainter] instance.
///
/// The `scale` must be a multiple of 2, for example 2, 4, 6, 8, 12 ...
pub fn new(hwnd: HWND, scale: i32) -> Self {
let light_theme = match is_light_theme() {
Ok(v) => v,
Err(_) => {
warn!("Fail to get system theme");
false
}
};
let (fg_color, bg_color) = match light_theme {
true => (FG_LIGHT_COLOR, BG_LIGHT_COLOR),
false => (FG_DARK_COLOR, BG_DARK_COLOR),
};
GdiAAPainter {
mem_hdc: Default::default(),
mem_map: Default::default(),
Expand All @@ -52,6 +73,8 @@ impl GdiAAPainter {
height: 0,
size: 0,
scale,
fg_color,
bg_color,
}
}

Expand Down Expand Up @@ -86,7 +109,7 @@ impl GdiAAPainter {
let mem_map = CreateCompatibleBitmap(hdc, width, height);
SelectObject(mem_dc, mem_map);

let brush = CreateSolidBrush(BG_COLOR);
let brush = CreateSolidBrush(self.fg_color);
let rect = RECT {
left: 0,
top: 0,
Expand Down Expand Up @@ -164,7 +187,7 @@ impl GdiAAPainter {
right: self.width * self.scale,
bottom: self.width * self.scale,
};
FillRect(self.scaled_hdc, &rect as _, CreateSolidBrush(FG_COLOR));
FillRect(self.scaled_hdc, &rect as _, CreateSolidBrush(self.fg_color));

let cy = (WINDOW_BORDER_SIZE + ICON_BORDER_SIZE) * self.scale;
let brush_icon = HBRUSH::default();
Expand All @@ -183,7 +206,7 @@ impl GdiAAPainter {
right,
bottom,
};
FillRect(self.scaled_hdc, &rect as _, CreateSolidBrush(BG_COLOR));
FillRect(self.scaled_hdc, &rect as _, CreateSolidBrush(self.bg_color));
}

let cx = cy + item_size * (i as i32);
Expand All @@ -202,3 +225,12 @@ impl GdiAAPainter {
}
}
}

fn is_light_theme() -> Result<bool> {
let reg_key = RegKey::new_hkcu(
w!("Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"),
w!("SystemUsesLightTheme"),
)?;
let value = reg_key.get_int()?;
Ok(value == 1)
}
32 changes: 31 additions & 1 deletion src/utils/regedit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ use windows::core::PCWSTR;
use windows::Win32::Foundation::ERROR_FILE_NOT_FOUND;
use windows::Win32::System::Registry::{
RegCloseKey, RegDeleteValueW, RegGetValueW, RegOpenKeyExW, RegSetValueExW, HKEY,
HKEY_CURRENT_USER, KEY_ALL_ACCESS, REG_SZ, REG_VALUE_TYPE, RRF_RT_REG_SZ,
HKEY_CURRENT_USER, KEY_ALL_ACCESS, REG_DWORD_BIG_ENDIAN, REG_SZ, REG_VALUE_TYPE,
RRF_RT_REG_DWORD, RRF_RT_REG_SZ,
};

#[derive(Debug)]
Expand Down Expand Up @@ -57,6 +58,35 @@ impl RegKey {
Ok(Some(buffer[..len].to_vec()))
}

pub fn get_int(&self) -> Result<u32> {
let mut value: [u8; 4] = Default::default();
let mut size: u32 = std::mem::size_of_val(&value) as u32;
let mut kind: REG_VALUE_TYPE = Default::default();
let ret = unsafe {
RegGetValueW(
self.hkey,
None,
self.name,
RRF_RT_REG_DWORD,
Some(&mut kind),
Some(value.as_mut_ptr() as *mut _),
Some(&mut size),
)
};
if ret.is_err() {
bail!(
"Fail to get reg value, {:?}",
windows::core::Error::from(ret)
);
}
let value = if kind == REG_DWORD_BIG_ENDIAN {
u32::from_be_bytes(value)
} else {
u32::from_le_bytes(value)
};
Ok(value)
}

pub fn set_value(&self, value: &[u8]) -> Result<()> {
unsafe { RegSetValueExW(self.hkey, self.name, 0, REG_SZ, Some(value)) }
.ok()
Expand Down