Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/utils/app_icon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -196,6 +200,34 @@ pub fn get_window_icon(hwnd: HWND) -> Option<HICON> {
None
}

fn get_browser_profile_icon(module_path: &str) -> Option<HICON> {
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<HICON> {
let parts: Vec<&str> = module_path.split("::").collect();
if parts.len() != 3 {
Expand Down
97 changes: 68 additions & 29 deletions src/utils/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,35 +161,67 @@ fn get_aumid(hwnd: HWND) -> Option<String> {
Some(propvar.to_string())
}

fn get_edge_pwa_aumid_info(hwnd: HWND) -> Option<String> {
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<String>, Option<String>) {
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<String>, Option<String>) {
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 {
Expand All @@ -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);
Expand Down Expand Up @@ -316,6 +348,8 @@ pub(crate) fn get_default_user_data_dir(module_path: &str) -> Option<String> {
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;
};
Expand Down Expand Up @@ -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()
Expand Down
Loading