windows: display icon (#9571)

Now `Zed` can display icons. The image below shows the icon of the
`zed.exe` file and the icon in the right-click properties.

![Screenshot 2024-03-20
181054](https://github.com/zed-industries/zed/assets/14981363/8f1ccc7f-aab0-46cf-8c32-a3545ba710a3)

I used the `crates\zed\resources\app-icon@2x.png` file to generate the
`.ico` file. Due to some blank space around the logo in the original
file, the logo appears slightly smaller on Windows compared to other
software.

![Screenshot 2024-03-20
181155](https://github.com/zed-industries/zed/assets/14981363/874c5ed3-6796-428c-9a91-f91231bb6510)

The current `.ico` file contains logo files of multiple sizes: 16x16,
24x24, 32x32, 48x48, 64x64, 96x96, 128x128, 256x256, 512x512.

Release Notes:

- N/A
This commit is contained in:
张小白 2024-03-22 00:30:01 +08:00 committed by GitHub
parent f179158913
commit 3fd62a2313
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 28 additions and 5 deletions

View file

@ -14,7 +14,7 @@ use std::{
}; };
use ::util::{ResultExt, SemanticVersion}; use ::util::{ResultExt, SemanticVersion};
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Context, Result};
use async_task::Runnable; use async_task::Runnable;
use copypasta::{ClipboardContext, ClipboardProvider}; use copypasta::{ClipboardContext, ClipboardProvider};
use futures::channel::oneshot::{self, Receiver}; use futures::channel::oneshot::{self, Receiver};
@ -62,6 +62,7 @@ pub(crate) struct WindowsPlatformInner {
pub raw_window_handles: RwLock<SmallVec<[HWND; 4]>>, pub raw_window_handles: RwLock<SmallVec<[HWND; 4]>>,
pub(crate) dispatch_event: OwnedHandle, pub(crate) dispatch_event: OwnedHandle,
pub(crate) settings: RefCell<WindowsPlatformSystemSettings>, pub(crate) settings: RefCell<WindowsPlatformSystemSettings>,
pub icon: HICON,
} }
impl WindowsPlatformInner { impl WindowsPlatformInner {
@ -156,6 +157,7 @@ impl WindowsPlatform {
let callbacks = Mutex::new(Callbacks::default()); let callbacks = Mutex::new(Callbacks::default());
let raw_window_handles = RwLock::new(SmallVec::new()); let raw_window_handles = RwLock::new(SmallVec::new());
let settings = RefCell::new(WindowsPlatformSystemSettings::new()); let settings = RefCell::new(WindowsPlatformSystemSettings::new());
let icon = load_icon().unwrap_or_default();
let inner = Rc::new(WindowsPlatformInner { let inner = Rc::new(WindowsPlatformInner {
background_executor, background_executor,
foreground_executor, foreground_executor,
@ -165,6 +167,7 @@ impl WindowsPlatform {
raw_window_handles, raw_window_handles,
dispatch_event, dispatch_event,
settings, settings,
icon,
}); });
Self { inner } Self { inner }
} }
@ -881,3 +884,19 @@ fn fallback_vsync_fn() -> impl Fn(HANDLE) -> bool + Send {
(unsafe { WaitForSingleObject(timer_stop_event, interval) }) == WAIT_TIMEOUT (unsafe { WaitForSingleObject(timer_stop_event, interval) }) == WAIT_TIMEOUT
} }
} }
fn load_icon() -> Result<HICON> {
let module = unsafe { GetModuleHandleW(None).context("unable to get module handle")? };
let handle = unsafe {
LoadImageW(
module,
IDI_APPLICATION,
IMAGE_ICON,
0,
0,
LR_DEFAULTSIZE | LR_SHARED,
)
.context("unable to load icon file")?
};
Ok(HICON(handle.0))
}

View file

@ -1097,7 +1097,7 @@ impl WindowsWindow {
handle: AnyWindowHandle, handle: AnyWindowHandle,
options: WindowParams, options: WindowParams,
) -> Self { ) -> Self {
let classname = register_wnd_class(); let classname = register_wnd_class(platform_inner.icon);
let hide_title_bar = options let hide_title_bar = options
.titlebar .titlebar
.as_ref() .as_ref()
@ -1556,13 +1556,14 @@ impl IDropTarget_Impl for WindowsDragDropHandler {
} }
} }
fn register_wnd_class() -> PCWSTR { fn register_wnd_class(icon_handle: HICON) -> PCWSTR {
const CLASS_NAME: PCWSTR = w!("Zed::Window"); const CLASS_NAME: PCWSTR = w!("Zed::Window");
static ONCE: Once = Once::new(); static ONCE: Once = Once::new();
ONCE.call_once(|| { ONCE.call_once(|| {
let wc = WNDCLASSW { let wc = WNDCLASSW {
lpfnWndProc: Some(wnd_proc), lpfnWndProc: Some(wnd_proc),
hIcon: icon_handle,
hCursor: unsafe { LoadCursorW(None, IDC_ARROW).ok().unwrap() }, hCursor: unsafe { LoadCursorW(None, IDC_ARROW).ok().unwrap() },
lpszClassName: PCWSTR(CLASS_NAME.as_ptr()), lpszClassName: PCWSTR(CLASS_NAME.as_ptr()),
style: CS_HREDRAW | CS_VREDRAW, style: CS_HREDRAW | CS_VREDRAW,

View file

@ -50,15 +50,18 @@ fn main() {
println!("cargo:rustc-link-arg=/stack:{}", 8 * 1024 * 1024); println!("cargo:rustc-link-arg=/stack:{}", 8 * 1024 * 1024);
let manifest = std::path::Path::new("resources/windows/manifest.xml"); let manifest = std::path::Path::new("resources/windows/manifest.xml");
let icon = std::path::Path::new("resources/windows/app-icon.ico");
println!("cargo:rerun-if-changed={}", manifest.display()); println!("cargo:rerun-if-changed={}", manifest.display());
println!("cargo:rustc-link-arg-bins=/MANIFEST:EMBED"); println!("cargo:rerun-if-changed={}", icon.display());
println!("cargo:rustc-link-arg-bins=/MANIFEST:EMBED");
println!( println!(
"cargo:rustc-link-arg-bins=/MANIFESTINPUT:{}", "cargo:rustc-link-arg-bins=/MANIFESTINPUT:{}",
manifest.canonicalize().unwrap().display() manifest.canonicalize().unwrap().display()
); );
let res = winresource::WindowsResource::new(); let mut res = winresource::WindowsResource::new();
res.set_icon(icon.to_str().unwrap());
if let Err(e) = res.compile() { if let Err(e) = res.compile() {
eprintln!("{}", e); eprintln!("{}", e);
std::process::exit(1); std::process::exit(1);

Binary file not shown.

After

Width:  |  Height:  |  Size: 577 KiB