Fix Windows badge API for windows-rs 0.61 + add libfuse2 for Linux AppImage
- Move BOOL import to windows::core (removed from Win32::Foundation in 0.61) - Move CreateBitmap import from WindowsAndMessaging to Win32::Graphics::Gdi - Wrap nullable handles in Some() for GetDC, CreateCompatibleDC, CreateDIBSection, ReleaseDC (new Option<T> API in 0.61) - Add .into() for all SelectObject/DeleteObject GDI handle args (now HGDIOBJ) - Use FONT_PITCH_AND_FAMILY type directly in CreateFontW instead of u32 cast - Make DrawTextW slice mutable (&mut [u16] required in 0.61) - Use hicon.unwrap_or_default() for SetOverlayIcon (takes HICON not Option<HICON>) - Add libfuse2 to apt-get for Linux AppImage bundler (FUSE mount fallback) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -134,7 +134,8 @@ jobs:
|
||||
libayatana-appindicator3-dev \
|
||||
librsvg2-dev \
|
||||
patchelf \
|
||||
xdg-utils
|
||||
xdg-utils \
|
||||
libfuse2
|
||||
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
|
||||
+47
-36
@@ -97,21 +97,20 @@ fn set_badge_count(count: u32, window: tauri::Window) -> Result<(), String> {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
use windows::{
|
||||
core::PCWSTR,
|
||||
core::{BOOL, PCWSTR},
|
||||
Win32::{
|
||||
Foundation::{BOOL, COLORREF, HWND, RECT},
|
||||
Foundation::{COLORREF, HWND, RECT},
|
||||
Graphics::Gdi::{
|
||||
CreateCompatibleDC, CreateDIBSection, CreatePen, CreateSolidBrush,
|
||||
DeleteDC, DeleteObject, DIB_RGB_COLORS, DrawTextW, Ellipse,
|
||||
CreateBitmap, CreateCompatibleDC, CreateDIBSection, CreateFontW, CreatePen,
|
||||
CreateSolidBrush, DeleteDC, DeleteObject, DIB_RGB_COLORS, DrawTextW, Ellipse,
|
||||
ReleaseDC, SelectObject, SetBkMode, SetTextColor, BITMAPINFO,
|
||||
BITMAPINFOHEADER, BI_RGB, DT_CENTER, DT_SINGLELINE, DT_VCENTER,
|
||||
PS_NULL, TRANSPARENT, CreateFontW, DEFAULT_CHARSET, DEFAULT_PITCH,
|
||||
DEFAULT_QUALITY, CLIP_DEFAULT_PRECIS, FW_BOLD, FF_DONTCARE,
|
||||
OUT_DEFAULT_PRECIS,
|
||||
BITMAPINFOHEADER, BI_RGB, CLIP_DEFAULT_PRECIS, DEFAULT_CHARSET, DEFAULT_PITCH,
|
||||
DEFAULT_QUALITY, DT_CENTER, DT_SINGLELINE, DT_VCENTER, FF_DONTCARE,
|
||||
FONT_PITCH_AND_FAMILY, FW_BOLD, OUT_DEFAULT_PRECIS, PS_NULL, TRANSPARENT,
|
||||
},
|
||||
UI::{
|
||||
Shell::{ITaskbarList3, TaskbarList},
|
||||
WindowsAndMessaging::{CreateBitmap, CreateIconIndirect, DestroyIcon, ICONINFO},
|
||||
WindowsAndMessaging::{CreateIconIndirect, DestroyIcon, HICON, ICONINFO},
|
||||
},
|
||||
System::Com::{CoCreateInstance, CLSCTX_INPROC_SERVER},
|
||||
},
|
||||
@@ -119,18 +118,18 @@ fn set_badge_count(count: u32, window: tauri::Window) -> Result<(), String> {
|
||||
|
||||
let hwnd = HWND(window.hwnd().map_err(|e| e.to_string())?.0 as _);
|
||||
|
||||
let hicon = if count > 0 {
|
||||
let hicon: Option<HICON> = if count > 0 {
|
||||
let label = if count > 99 {
|
||||
"99+".to_string()
|
||||
} else {
|
||||
count.to_string()
|
||||
};
|
||||
let label_wide: Vec<u16> = label.encode_utf16().chain(std::iter::once(0)).collect();
|
||||
let mut label_wide: Vec<u16> = label.encode_utf16().chain(std::iter::once(0)).collect();
|
||||
|
||||
unsafe {
|
||||
let size = 16i32;
|
||||
let hdc_screen = windows::Win32::Graphics::Gdi::GetDC(HWND(std::ptr::null_mut()));
|
||||
let hdc = CreateCompatibleDC(hdc_screen);
|
||||
let hdc_screen = windows::Win32::Graphics::Gdi::GetDC(None);
|
||||
let hdc = CreateCompatibleDC(Some(hdc_screen));
|
||||
|
||||
let bmi = BITMAPINFO {
|
||||
bmiHeader: BITMAPINFOHEADER {
|
||||
@@ -145,32 +144,41 @@ fn set_badge_count(count: u32, window: tauri::Window) -> Result<(), String> {
|
||||
..Default::default()
|
||||
};
|
||||
let mut bits: *mut std::ffi::c_void = std::ptr::null_mut();
|
||||
let hbm_color = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &mut bits, None, 0)
|
||||
.map_err(|e| e.to_string())?;
|
||||
let old_bm = SelectObject(hdc, hbm_color);
|
||||
let hbm_color =
|
||||
CreateDIBSection(Some(hdc), &bmi, DIB_RGB_COLORS, &mut bits, None, 0)
|
||||
.map_err(|e| e.to_string())?;
|
||||
let old_bm = SelectObject(hdc, hbm_color.into());
|
||||
|
||||
let hbrush = CreateSolidBrush(COLORREF(0x003030DD));
|
||||
let old_brush = SelectObject(hdc, hbrush);
|
||||
let old_brush = SelectObject(hdc, hbrush.into());
|
||||
let hpen = CreatePen(PS_NULL, 0, COLORREF(0));
|
||||
let old_pen = SelectObject(hdc, hpen);
|
||||
let old_pen = SelectObject(hdc, hpen.into());
|
||||
let _ = Ellipse(hdc, 0, 0, size, size);
|
||||
|
||||
let hfont = CreateFontW(
|
||||
11, 0, 0, 0, FW_BOLD.0 as i32, 0, 0, 0,
|
||||
DEFAULT_CHARSET.0 as u32,
|
||||
OUT_DEFAULT_PRECIS.0 as u32,
|
||||
CLIP_DEFAULT_PRECIS.0 as u32,
|
||||
DEFAULT_QUALITY.0 as u32,
|
||||
(DEFAULT_PITCH.0 | FF_DONTCARE.0) as u32,
|
||||
11,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
FW_BOLD.0 as i32,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
DEFAULT_CHARSET,
|
||||
OUT_DEFAULT_PRECIS,
|
||||
CLIP_DEFAULT_PRECIS,
|
||||
DEFAULT_QUALITY,
|
||||
FONT_PITCH_AND_FAMILY(DEFAULT_PITCH.0 | FF_DONTCARE.0),
|
||||
windows::core::w!("Segoe UI"),
|
||||
);
|
||||
let old_font = SelectObject(hdc, hfont);
|
||||
let old_font = SelectObject(hdc, hfont.into());
|
||||
SetTextColor(hdc, COLORREF(0x00FFFFFF));
|
||||
let _ = SetBkMode(hdc, TRANSPARENT);
|
||||
let mut rect = RECT { left: 0, top: 0, right: size, bottom: size };
|
||||
let label_len = label_wide.len() - 1;
|
||||
let _ = DrawTextW(
|
||||
hdc,
|
||||
&label_wide[..label_wide.len() - 1],
|
||||
&mut label_wide[..label_len],
|
||||
&mut rect,
|
||||
DT_CENTER | DT_VCENTER | DT_SINGLELINE,
|
||||
);
|
||||
@@ -179,12 +187,12 @@ fn set_badge_count(count: u32, window: tauri::Window) -> Result<(), String> {
|
||||
SelectObject(hdc, old_pen);
|
||||
SelectObject(hdc, old_font);
|
||||
SelectObject(hdc, old_bm);
|
||||
let _ = DeleteObject(hbrush);
|
||||
let _ = DeleteObject(hpen);
|
||||
let _ = DeleteObject(hfont);
|
||||
let _ = DeleteObject(hbrush.into());
|
||||
let _ = DeleteObject(hpen.into());
|
||||
let _ = DeleteObject(hfont.into());
|
||||
|
||||
let hbm_mask = CreateBitmap(size, size, 1, 1, None)
|
||||
.map_err(|e| { let _ = DeleteObject(hbm_color); e.to_string() })?;
|
||||
.map_err(|e| { let _ = DeleteObject(hbm_color.into()); e.to_string() })?;
|
||||
|
||||
let icon_info = ICONINFO {
|
||||
fIcon: BOOL(1),
|
||||
@@ -193,13 +201,16 @@ fn set_badge_count(count: u32, window: tauri::Window) -> Result<(), String> {
|
||||
hbmMask: hbm_mask,
|
||||
hbmColor: hbm_color,
|
||||
};
|
||||
let hicon = CreateIconIndirect(&icon_info)
|
||||
.map_err(|e| { let _ = DeleteObject(hbm_color); let _ = DeleteObject(hbm_mask); e.to_string() })?;
|
||||
let hicon = CreateIconIndirect(&icon_info).map_err(|e| {
|
||||
let _ = DeleteObject(hbm_color.into());
|
||||
let _ = DeleteObject(hbm_mask.into());
|
||||
e.to_string()
|
||||
})?;
|
||||
|
||||
let _ = DeleteObject(hbm_color);
|
||||
let _ = DeleteObject(hbm_mask);
|
||||
let _ = DeleteObject(hbm_color.into());
|
||||
let _ = DeleteObject(hbm_mask.into());
|
||||
let _ = DeleteDC(hdc);
|
||||
let _ = ReleaseDC(HWND(std::ptr::null_mut()), hdc_screen);
|
||||
let _ = ReleaseDC(None, hdc_screen);
|
||||
|
||||
Some(hicon)
|
||||
}
|
||||
@@ -213,7 +224,7 @@ fn set_badge_count(count: u32, window: tauri::Window) -> Result<(), String> {
|
||||
.map_err(|e| e.to_string())?;
|
||||
taskbar.HrInit().map_err(|e| e.to_string())?;
|
||||
taskbar
|
||||
.SetOverlayIcon(hwnd, hicon, PCWSTR::null())
|
||||
.SetOverlayIcon(hwnd, hicon.unwrap_or_default(), PCWSTR::null())
|
||||
.map_err(|e| e.to_string())?;
|
||||
if let Some(icon) = hicon {
|
||||
let _ = DestroyIcon(icon);
|
||||
|
||||
Reference in New Issue
Block a user