From 84a43a2e6afbdfab92c610d47aa75e3876ffacd6 Mon Sep 17 00:00:00 2001 From: SulfurNitride Date: Thu, 12 Mar 2026 13:48:25 -0500 Subject: Replace wrestool with native Rust PE icon extraction (pelite) - Add icons.rs to nak crate: parses PE resource sections, extracts RT_GROUP_ICON/RT_ICON and builds ICO files in memory - Expose nak_extract_exe_icon() FFI for C++ consumption - Update iconForExecutable() to use Rust FFI instead of shelling out to wrestool; reads all ICO entries for correct color depth - Fix BasicGamePlugin::gameIcon() to call iconForExecutable() (was returning empty QIcon, causing placeholder icons for BG3/Cyberpunk) - Move app icon setup: setDesktopFileName + setWindowIcon to MOApplication constructor (fixes Wayland taskbar/decoration icon) - Move data/com.fluorine.* to data/icons/, install to XDG paths at launch for Wayland compositor icon resolution - Remove icoutils dependency from Docker image and build output Co-Authored-By: Claude Opus 4.6 --- libs/nak_ffi/src/lib.rs | 51 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'libs/nak_ffi/src') diff --git a/libs/nak_ffi/src/lib.rs b/libs/nak_ffi/src/lib.rs index 65592fa..c45481b 100644 --- a/libs/nak_ffi/src/lib.rs +++ b/libs/nak_ffi/src/lib.rs @@ -614,6 +614,57 @@ pub extern "C" fn nak_get_dxvk_conf_path() -> *mut c_char { to_cstring(&path.to_string_lossy()) } +// ============================================================================ +// Tier 8: PE Icon Extraction +// ============================================================================ + +/// Result of icon extraction +#[repr(C)] +pub struct NakIconData { + /// Raw ICO file bytes (caller must free with nak_icon_data_free) + pub data: *mut u8, + /// Length of the data in bytes (0 if extraction failed) + pub len: usize, +} + +/// Extract the best icon from a Windows PE executable (.exe/.dll). +/// +/// Returns NakIconData with the raw ICO file bytes. +/// If extraction fails, data is null and len is 0. +/// Caller must free the result with nak_icon_data_free(). +#[no_mangle] +pub unsafe extern "C" fn nak_extract_exe_icon(exe_path: *const c_char) -> NakIconData { + let path_str = unsafe { from_cstr(exe_path) }; + if path_str.is_empty() { + return NakIconData { + data: ptr::null_mut(), + len: 0, + }; + } + + match nak_rust::icons::extract_icon(std::path::Path::new(path_str)) { + Some(bytes) => { + let len = bytes.len(); + let mut boxed = bytes.into_boxed_slice(); + let ptr = boxed.as_mut_ptr(); + std::mem::forget(boxed); + NakIconData { data: ptr, len } + } + None => NakIconData { + data: ptr::null_mut(), + len: 0, + }, + } +} + +/// Free icon data returned by nak_extract_exe_icon +#[no_mangle] +pub unsafe extern "C" fn nak_icon_data_free(icon: NakIconData) { + if !icon.data.is_null() && icon.len > 0 { + let _ = unsafe { Vec::from_raw_parts(icon.data, icon.len, icon.len) }; + } +} + // ============================================================================ // General: String free // ============================================================================ -- cgit v1.3.1