diff --git a/src/utils/app_icon.rs b/src/utils/app_icon.rs index 14edf23..0cc8a51 100644 --- a/src/utils/app_icon.rs +++ b/src/utils/app_icon.rs @@ -57,6 +57,10 @@ pub fn get_app_icon( return icon; } + if let Some(icon) = get_browser_profile_icon(module_path) { + return icon; + } + if module_path.starts_with("C:\\Program Files\\WindowsApps") { if let Some(icon) = get_appx_logo_path(module_path).and_then(|image_path| load_image_as_hicon(&image_path)) @@ -196,6 +200,34 @@ pub fn get_window_icon(hwnd: HWND) -> Option { None } +fn get_browser_profile_icon(module_path: &str) -> Option { + let parts: Vec<&str> = module_path.split("::").collect(); + if parts.len() != 2 { + return None; + } + let exe_path = parts[0]; + let profile = parts[1]; + + let local_app_data = std::env::var("LOCALAPPDATA").ok()?; + let (user_data_dir, icon_file) = if exe_path.to_lowercase().contains("chrome.exe") { + ( + PathBuf::from(&local_app_data).join(r"Google\Chrome\User Data"), + "Google Profile.ico", + ) + } else if exe_path.to_lowercase().contains("msedge.exe") { + ( + PathBuf::from(&local_app_data).join(r"Microsoft\Edge\User Data"), + "Edge Profile.ico", + ) + } else { + return None; + }; + + let profile_dir = super::window::pwa_map_profile_dir(profile); + let icon_path = user_data_dir.join(&profile_dir).join(icon_file); + load_image_as_hicon(&icon_path) +} + fn get_pwa_icon_from_lnk(module_path: &str) -> Option { let parts: Vec<&str> = module_path.split("::").collect(); if parts.len() != 3 { diff --git a/src/utils/window.rs b/src/utils/window.rs index b1aad3a..ee10e2e 100644 --- a/src/utils/window.rs +++ b/src/utils/window.rs @@ -161,35 +161,67 @@ fn get_aumid(hwnd: HWND) -> Option { Some(propvar.to_string()) } -fn get_edge_pwa_aumid_info(hwnd: HWND) -> Option { - let aumid = get_aumid(hwnd)?; - let pkg = aumid.strip_suffix("!App")?; - if pkg.is_empty() { - return None; +fn get_edge_aumid_info(hwnd: HWND) -> (Option, Option) { + let aumid = match get_aumid(hwnd) { + Some(v) => v, + None => return (None, None), + }; + + if let Some(pkg) = aumid.strip_suffix("!App") { + if !pkg.is_empty() { + return (None, Some(pkg.to_string())); + } + return (None, None); + } + + if aumid == "MSEdge" || aumid.is_empty() { + return (None, None); } - Some(pkg.to_string()) + if let Some(profile) = aumid.strip_prefix("MSEdge.UserData.") { + if !profile.is_empty() { + return (Some(profile.to_string()), None); + } + } + (None, None) } -fn get_chrome_pwa_aumid_info(hwnd: HWND) -> Option<(String, String)> { - let aumid = get_aumid(hwnd)?; +fn get_chrome_aumid_info(hwnd: HWND) -> (Option, Option) { + let aumid = match get_aumid(hwnd) { + Some(v) => v, + None => return (None, None), + }; let crx_prefix = "_crx_"; - let idx = aumid.find(crx_prefix)?; - let after_crx = &aumid[idx + crx_prefix.len()..]; - - let (app_id, profile) = if let Some(dot_idx) = after_crx.find(".UserData.") { - ( - &after_crx[..dot_idx], - &after_crx[dot_idx + ".UserData.".len()..], - ) - } else { - (after_crx, "Default") - }; + if let Some(idx) = aumid.find(crx_prefix) { + let after_crx = &aumid[idx + crx_prefix.len()..]; + let (app_id, profile) = if let Some(dot_idx) = after_crx.find(".UserData.") { + ( + &after_crx[..dot_idx], + &after_crx[dot_idx + ".UserData.".len()..], + ) + } else { + (after_crx, "Default") + }; + if !app_id.is_empty() && !profile.is_empty() { + let profile = if profile == "Default" { + None + } else { + Some(profile.to_string()) + }; + return (profile, Some(app_id.to_string())); + } + return (None, None); + } - if app_id.is_empty() || profile.is_empty() { - return None; + if aumid == "Chrome" || aumid.is_empty() { + return (None, None); + } + if let Some(profile) = aumid.strip_prefix("Chrome.UserData.") { + if !profile.is_empty() { + return (Some(profile.to_string()), None); + } } - Some((profile.to_string(), app_id.to_string())) + (None, None) } fn is_app_id_match(full: &str, truncated: &str) -> bool { @@ -209,7 +241,7 @@ fn is_app_id_match(full: &str, truncated: &str) -> bool { true } -fn pwa_map_profile_dir(aumid_profile: &str) -> String { +pub(crate) fn pwa_map_profile_dir(aumid_profile: &str) -> String { if let Some(num) = aumid_profile.strip_prefix("Profile") { if num.chars().all(|c| c.is_ascii_digit()) { return format!("Profile {}", num); @@ -316,6 +348,8 @@ pub(crate) fn get_default_user_data_dir(module_path: &str) -> Option { let local_app_data = std::env::var("LOCALAPPDATA").ok()?; let browser_path = if module_path.to_lowercase().contains("chrome.exe") { r"Google\Chrome\User Data" + } else if module_path.to_lowercase().contains("msedge.exe") { + r"Microsoft\Edge\User Data" } else { return None; }; @@ -438,14 +472,19 @@ pub fn list_windows( } } let key = if is_chrome_browser(&module_path) { - match get_chrome_pwa_aumid_info(hwnd) { - Some((profile, app_id)) => format!("{}::{}::{}", module_path, profile, app_id), - None => module_path.clone(), + match get_chrome_aumid_info(hwnd) { + (Some(profile), Some(app_id)) => { + format!("{}::{}::{}", module_path, profile, app_id) + } + (Some(profile), None) => format!("{}::{}", module_path, profile), + (None, Some(app_id)) => format!("{}::Default::{}", module_path, app_id), + (None, None) => module_path.clone(), } } else if is_edge_browser(&module_path) { - match get_edge_pwa_aumid_info(hwnd) { - Some(pkg) => format!("{}::appx::{}", module_path, pkg), - None => module_path.clone(), + match get_edge_aumid_info(hwnd) { + (None, Some(pkg)) => format!("{}::appx::{}", module_path, pkg), + (Some(profile), None) => format!("{}::{}", module_path, profile), + _ => module_path.clone(), } } else { module_path.clone()