Skip to content

Commit c6829ff

Browse files
fix missing taskbar icon
1 parent 57055e3 commit c6829ff

File tree

7 files changed

+60
-29
lines changed

7 files changed

+60
-29
lines changed

desktop/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,11 @@ windows = { version = "0.58.0", features = [
5454
"Win32_Graphics_Dwm",
5555
"Win32_Graphics_Gdi",
5656
"Win32_System_LibraryLoader",
57+
"Win32_System_Com",
5758
"Win32_UI_Controls",
5859
"Win32_UI_WindowsAndMessaging",
5960
"Win32_UI_HiDpi",
61+
"Win32_UI_Shell",
6062
] }
6163

6264
# macOS-specific dependencies

desktop/platform/win/build.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ fn main() {
1010
// TODO: Replace with actual version
1111
res.set_version_info(winres::VersionInfo::FILEVERSION, {
1212
const MAJOR: u64 = 0;
13-
const MINOR: u64 = 999;
13+
const MINOR: u64 = 0;
1414
const PATCH: u64 = 0;
1515
const RELEASE: u64 = 0;
1616
(MAJOR << 48) | (MINOR << 32) | (PATCH << 16) | RELEASE
1717
});
18-
res.set("FileVersion", "0.999.0.0");
19-
res.set("ProductVersion", "0.999.0.0");
18+
res.set("FileVersion", "0.0.0.0");
19+
res.set("ProductVersion", "0.0.0.0");
2020

2121
res.set("OriginalFilename", "Graphite.exe");
2222

desktop/src/app.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,10 @@ impl ApplicationHandler for App {
456456
let render_state = RenderState::new(self.window.as_ref().unwrap(), self.wgpu_context.clone());
457457
self.render_state = Some(render_state);
458458

459+
if let Some(window) = &self.window.as_ref() {
460+
window.show();
461+
}
462+
459463
self.resize();
460464

461465
self.desktop_wrapper.init(self.wgpu_context.clone());

desktop/src/consts.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
pub(crate) const APP_NAME: &str = "Graphite";
2-
#[cfg(target_os = "linux")]
2+
#[cfg(any(target_os = "linux", target_os = "windows"))]
33
pub(crate) const APP_ID: &str = "art.graphite.Graphite";
44

55
pub(crate) const APP_DIRECTORY_NAME: &str = "graphite";

desktop/src/window.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ impl Window {
5252
.with_min_surface_size(winit::dpi::LogicalSize::new(400, 300))
5353
.with_surface_size(winit::dpi::LogicalSize::new(1200, 800))
5454
.with_resizable(true)
55+
.with_visible(false)
5556
.with_theme(Some(winit::window::Theme::Dark));
5657

5758
attributes = native::NativeWindowImpl::configure(attributes, event_loop);
@@ -67,6 +68,10 @@ impl Window {
6768
}
6869
}
6970

71+
pub(crate) fn show(&self) {
72+
self.winit_window.set_visible(true);
73+
}
74+
7075
pub(crate) fn request_redraw(&self) {
7176
self.winit_window.request_redraw();
7277
}

desktop/src/window/win.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,27 @@
1-
use winit::dpi::PhysicalSize;
1+
use windows::Win32::System::Com::{COINIT_APARTMENTTHREADED, CoInitializeEx};
2+
use windows::Win32::UI::Shell::SetCurrentProcessExplicitAppUserModelID;
3+
use windows::core::HSTRING;
24
use winit::event_loop::ActiveEventLoop;
3-
use winit::icon::Icon;
4-
use winit::platform::windows::{WinIcon, WindowAttributesWindows};
55
use winit::window::{Window, WindowAttributes};
66

7+
use crate::consts::APP_ID;
78
use crate::event::AppEventScheduler;
89

910
pub(super) struct NativeWindowImpl {
1011
native_handle: native_handle::NativeWindowHandle,
1112
}
1213

1314
impl super::NativeWindow for NativeWindowImpl {
15+
fn init() {
16+
let app_id = HSTRING::from(APP_ID);
17+
unsafe {
18+
let _ = CoInitializeEx(None, COINIT_APARTMENTTHREADED).ok();
19+
SetCurrentProcessExplicitAppUserModelID(&app_id).ok();
20+
}
21+
}
22+
1423
fn configure(attributes: WindowAttributes, _event_loop: &dyn ActiveEventLoop) -> WindowAttributes {
15-
let icon = WinIcon::from_resource(1, Some(PhysicalSize::new(256, 256))).ok().map(|icon| Icon(std::sync::Arc::new(icon)));
16-
let win_window = WindowAttributesWindows::default().with_taskbar_icon(icon);
17-
let icon = WinIcon::from_resource(1, None).ok().map(|icon| Icon(std::sync::Arc::new(icon)));
18-
attributes.with_window_icon(icon).with_platform_attributes(Box::new(win_window))
24+
attributes
1925
}
2026

2127
fn new(window: &dyn Window, _app_event_scheduler: AppEventScheduler) -> Self {

desktop/src/window/win/native_handle.rs

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub(super) struct NativeWindowHandle {
3030
impl NativeWindowHandle {
3131
pub(super) fn new(window: &dyn Window) -> NativeWindowHandle {
3232
// Extract Win32 HWND from winit.
33-
let hwnd = match window.window_handle().expect("No window handle").as_raw() {
33+
let main = match window.window_handle().expect("No window handle").as_raw() {
3434
RawWindowHandle::Win32(h) => HWND(h.hwnd.get() as *mut std::ffi::c_void),
3535
_ => panic!("Not a Win32 window"),
3636
};
@@ -57,55 +57,69 @@ impl NativeWindowHandle {
5757
None,
5858
HINSTANCE(std::ptr::null_mut()),
5959
// Pass the main window's HWND to WM_NCCREATE so the helper can store it.
60-
Some(&hwnd as *const _ as _),
60+
Some(&main as *const _ as _),
6161
)
6262
}
6363
.expect("CreateWindowExW failed");
6464

6565
// Subclass the main window.
6666
// https://learn.microsoft.com/windows/win32/api/winuser/nf-winuser-setwindowlongptra
67-
let prev_window_message_handler = unsafe { SetWindowLongPtrW(hwnd, GWLP_WNDPROC, main_window_handle_message as isize) };
67+
let prev_window_message_handler = unsafe { SetWindowLongPtrW(main, GWLP_WNDPROC, main_window_handle_message as isize) };
6868
if prev_window_message_handler == 0 {
6969
let _ = unsafe { DestroyWindow(helper) };
7070
panic!("SetWindowLongPtrW failed");
7171
}
7272

73-
let inner = NativeWindowHandle {
74-
main: hwnd,
73+
let native_handle = NativeWindowHandle {
74+
main,
7575
helper,
7676
prev_window_message_handler,
7777
};
78-
registry::insert(&inner);
78+
registry::insert(&native_handle);
7979

8080
// Place the helper over the main window and show it without activation.
81-
unsafe { position_helper(hwnd, helper) };
81+
unsafe { position_helper(main, helper) };
8282
let _ = unsafe { ShowWindow(helper, SW_SHOWNOACTIVATE) };
8383

8484
// DwmExtendFrameIntoClientArea is needed to keep native window frame (but no titlebar).
8585
// https://learn.microsoft.com/windows/win32/api/dwmapi/nf-dwmapi-dwmextendframeintoclientarea
8686
// https://learn.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
8787
let mut boarder_size: u32 = 1;
88-
let _ = unsafe { DwmGetWindowAttribute(hwnd, DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, &mut boarder_size as *mut _ as *mut _, size_of::<u32>() as u32) };
88+
let _ = unsafe { DwmGetWindowAttribute(main, DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, &mut boarder_size as *mut _ as *mut _, size_of::<u32>() as u32) };
8989
let margins = MARGINS {
9090
cxLeftWidth: 0,
9191
cxRightWidth: 0,
9292
cyBottomHeight: 0,
9393
cyTopHeight: boarder_size as i32,
9494
};
95-
let _ = unsafe { DwmExtendFrameIntoClientArea(hwnd, &margins) };
95+
let _ = unsafe { DwmExtendFrameIntoClientArea(main, &margins) };
96+
97+
let hinst = unsafe { GetModuleHandleW(None) }.unwrap();
98+
99+
// Set taskbar icon
100+
if let Ok(big) = unsafe { LoadImageW(hinst, PCWSTR(1usize as *const u16), IMAGE_ICON, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_SHARED) } {
101+
unsafe { SetClassLongPtrW(main, GCLP_HICON, big.0 as isize) };
102+
unsafe { SendMessageW(main, WM_SETICON, WPARAM(ICON_BIG as usize), LPARAM(big.0 as isize)) };
103+
}
104+
105+
// Set window icon
106+
if let Ok(small) = unsafe { LoadImageW(hinst, PCWSTR(1usize as *const u16), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED) } {
107+
unsafe { SetClassLongPtrW(main, GCLP_HICONSM, small.0 as isize) };
108+
unsafe { SendMessageW(main, WM_SETICON, WPARAM(ICON_SMALL as usize), LPARAM(small.0 as isize)) };
109+
}
96110

97111
// Force window update
98-
let _ = unsafe { SetWindowPos(hwnd, None, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER) };
112+
let _ = unsafe { SetWindowPos(main, None, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER) };
99113

100-
inner
114+
native_handle
101115
}
102116

103117
pub(super) fn destroy(&self) {
104118
registry::remove_by_main(self.main);
105119

106120
// Undo subclassing and destroy the helper window.
107121
let _ = unsafe { SetWindowLongPtrW(self.main, GWLP_WNDPROC, self.prev_window_message_handler) };
108-
if self.helper.0 != std::ptr::null_mut() {
122+
if !self.helper.is_invalid() {
109123
let _ = unsafe { DestroyWindow(self.helper) };
110124
}
111125
}
@@ -264,16 +278,17 @@ unsafe extern "system" fn helper_window_handle_message(hwnd: HWND, msg: u32, wpa
264278
unsafe { DefWindowProcW(hwnd, msg, wparam, lparam) }
265279
}
266280

281+
const RESIZE_BAND_THICKNESS: i32 = 8;
282+
267283
// Position the helper window to match the main window's location and size (plus the resize band size).
268284
unsafe fn position_helper(main: HWND, helper: HWND) {
269285
let mut r = RECT::default();
270286
let _ = unsafe { GetWindowRect(main, &mut r) };
271287

272-
const RESIZE_BAND_SIZE: i32 = 8;
273-
let x = r.left - RESIZE_BAND_SIZE;
274-
let y = r.top - RESIZE_BAND_SIZE;
275-
let w = (r.right - r.left) + RESIZE_BAND_SIZE * 2;
276-
let h = (r.bottom - r.top) + RESIZE_BAND_SIZE * 2;
288+
let x = r.left - RESIZE_BAND_THICKNESS;
289+
let y = r.top - RESIZE_BAND_THICKNESS;
290+
let w = (r.right - r.left) + RESIZE_BAND_THICKNESS * 2;
291+
let h = (r.bottom - r.top) + RESIZE_BAND_THICKNESS * 2;
277292

278293
let _ = unsafe { SetWindowPos(helper, main, x, y, w, h, SWP_NOACTIVATE) };
279294
}
@@ -285,7 +300,6 @@ unsafe fn calculate_hit(helper: HWND, lparam: LPARAM) -> u32 {
285300
let mut r = RECT::default();
286301
let _ = unsafe { GetWindowRect(helper, &mut r) };
287302

288-
const RESIZE_BAND_THICKNESS: i32 = 8;
289303
let on_top = y < (r.top + RESIZE_BAND_THICKNESS) as u32;
290304
let on_right = x >= (r.right - RESIZE_BAND_THICKNESS) as u32;
291305
let on_bottom = y >= (r.bottom - RESIZE_BAND_THICKNESS) as u32;

0 commit comments

Comments
 (0)