Skip to content

Commit

Permalink
fix(weg): items display name
Browse files Browse the repository at this point in the history
  • Loading branch information
eythaann committed Dec 27, 2024
1 parent 2ef2858 commit 1649185
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 52 deletions.
17 changes: 5 additions & 12 deletions src/background/modules/media/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@ use windows::{
IMMNotificationClient, IMMNotificationClient_Impl, ISimpleAudioVolume,
MMDeviceEnumerator, DEVICE_STATE_ACTIVE,
},
Storage::EnhancedStorage::PKEY_FileDescription,
System::Com::{CLSCTX_ALL, STGM_READ},
UI::Shell::{PropertiesSystem::PROPERTYKEY, SIGDN_NORMALDISPLAY},
UI::Shell::PropertiesSystem::PROPERTYKEY,
},
};
use windows_core::Interface;
Expand All @@ -38,7 +37,7 @@ use crate::{
seelen_weg::icon_extractor::{extract_and_save_icon_from_file, extract_and_save_icon_umid},
trace_lock,
utils::pcwstr,
windows_api::{Com, WindowEnumerator, WindowsApi},
windows_api::{process::Process, Com, WindowEnumerator, WindowsApi},
};

use super::domain::{
Expand Down Expand Up @@ -475,16 +474,10 @@ impl MediaManager {

let name;
let icon_path;
match WindowsApi::exe_path_by_process(session.GetProcessId()?) {
let process = Process::from_id(session.GetProcessId()?);
match process.program_path() {
Ok(path) => {
let shell_item = WindowsApi::get_shell_item(&path)?;
name = match shell_item.GetString(&PKEY_FileDescription) {
Ok(description) => description.to_string()?,
Err(_) => shell_item
.GetDisplayName(SIGDN_NORMALDISPLAY)?
.to_string()?,
}
.replace(".exe", "");
name = WindowsApi::get_executable_display_name(&path)?;
icon_path = extract_and_save_icon_from_file(&path)
.ok()
.map(|p| p.to_string_lossy().to_string());
Expand Down
100 changes: 69 additions & 31 deletions src/background/seelen_weg/weg_items_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ use seelen_core::{
handlers::SeelenEvent,
state::{PinnedWegItemData, WegAppGroupItem, WegItem, WegItems, WegTemporalItemsVisibility},
};
use std::{collections::HashMap, sync::Arc};
use std::{collections::HashMap, ffi::OsStr, sync::Arc};
use tauri::Emitter;

use crate::{
error_handler::Result,
seelen::get_app_handle,
state::application::FULL_STATE,
windows_api::{window::Window, MonitorEnumerator},
windows_api::{window::Window, MonitorEnumerator, WindowsApi},
};

use super::{
Expand All @@ -24,6 +24,13 @@ lazy_static! {
Arc::new(Mutex::new(WegItemsImpl::new()));
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ShouldGetInfoFrom {
Package(String),
WindowPropertyStore(String),
Process,
}

#[derive(Debug, Clone)]
pub struct WegItemsImpl {
items: WegItems,
Expand Down Expand Up @@ -108,25 +115,66 @@ impl WegItemsImpl {
Err(_) => window.exe()?,
};

let package_id = window.process().package_app_user_model_id().ok();
let assigned_umid = window.app_user_model_id();
let umid = window
.process()
.package_app_user_model_id()
.ok()
.or_else(|| window.app_user_model_id());

let get_info_from = match &umid {
Some(umid) => {
if WindowsApi::is_uwp_package_id(umid) {
ShouldGetInfoFrom::Package(umid.clone())
} else {
ShouldGetInfoFrom::WindowPropertyStore(umid.clone())
}
}
None => ShouldGetInfoFrom::Process,
};

let mut display_name = window
.app_display_name()
.unwrap_or_else(|_| String::from("Unknown"));

let relaunch_command;
match get_info_from {
ShouldGetInfoFrom::Package(umid) => {
let _ = extract_and_save_icon_umid(&umid);
display_name = WindowsApi::get_uwp_app_info(&umid)?
.DisplayInfo()?
.DisplayName()?
.to_string_lossy();
relaunch_command = format!("\"explorer.exe\" shell:AppsFolder\\{umid}");
}
ShouldGetInfoFrom::WindowPropertyStore(umid) => {
let shortcut = Window::search_shortcut_with_same_umid(&umid);
if let Some(shortcut) = shortcut {
path = shortcut.clone();
display_name = path
.file_stem()
.unwrap_or_else(|| OsStr::new("Unknown"))
.to_string_lossy()
.to_string();
}

let relaunch_command = if let Some(umid) = package_id.as_ref() {
let _ = extract_and_save_icon_umid(umid);
format!("\"explorer.exe\" shell:AppsFolder\\{umid}")
} else if let Some(umid) = assigned_umid.as_ref() {
let shortcut = Window::search_shortcut_with_same_umid(umid);
if let Some(shortcut) = shortcut {
path = shortcut.clone();
let _ = extract_and_save_icon_from_file(&path);

// System.AppUserModel.RelaunchCommand and System.AppUserModel.RelaunchDisplayNameResource
// must always be set together. If one of those properties is not set, then neither is used.
// https://learn.microsoft.com/en-us/windows/win32/properties/props-system-appusermodel-relaunchcommand
if let (Some(win_relaunch_command), Some(relaunch_display_name)) =
(window.relaunch_command(), window.relaunch_display_name())
{
relaunch_command = win_relaunch_command;
display_name = relaunch_display_name;
} else {
relaunch_command = format!("\"explorer.exe\" shell:AppsFolder\\{umid}");
}
}
ShouldGetInfoFrom::Process => {
let _ = extract_and_save_icon_from_file(&path);
relaunch_command = path.to_string_lossy().to_string();
}
let _ = extract_and_save_icon_from_file(&path);
window
.relaunch_command()
.unwrap_or(format!("\"explorer.exe\" shell:AppsFolder\\{umid}"))
} else {
let _ = extract_and_save_icon_from_file(&path);
path.to_string_lossy().to_string()
};

// groups order documented on https://learn.microsoft.com/en-us/windows/win32/properties/props-system-appusermodel-id
Expand All @@ -135,15 +183,7 @@ impl WegItemsImpl {
for item in self.iter_all_mut() {
match item {
WegItem::Pinned(data) | WegItem::Temporal(data) => {
if package_id.as_ref().is_some_and(|umid| umid == &data.id) {
data.windows.push(WegAppGroupItem {
title: window.title(),
handle: window.address(),
});
return Ok(());
}

if assigned_umid.as_ref().is_some_and(|umid| umid == &data.id) {
if data.umid.is_some() && umid == data.umid {
data.windows.push(WegAppGroupItem {
title: window.title(),
handle: window.address(),
Expand All @@ -165,12 +205,10 @@ impl WegItemsImpl {

let data = PinnedWegItemData {
id: uuid::Uuid::new_v4().to_string(),
umid: package_id.or(assigned_umid),
umid,
path,
relaunch_command,
display_name: window
.app_display_name()
.unwrap_or_else(|_| "Unkown".to_string()),
display_name,
is_dir: false,
windows: vec![WegAppGroupItem {
title: window.title(),
Expand Down
37 changes: 29 additions & 8 deletions src/background/windows_api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ mod app_bar;
mod com;
mod iterator;
pub mod monitor;
mod process;
pub mod process;
mod string_utils;
pub mod window;

Expand All @@ -25,6 +25,7 @@ use std::{

use windows::{
core::{BSTR, GUID, PCWSTR, PWSTR},
ApplicationModel::AppInfo,
Storage::Streams::{
DataReader, IRandomAccessStreamReference, IRandomAccessStreamWithContentType,
},
Expand Down Expand Up @@ -62,6 +63,7 @@ use windows::{
Storage::{
EnhancedStorage::{
PKEY_AppUserModel_ID, PKEY_AppUserModel_RelaunchCommand,
PKEY_AppUserModel_RelaunchDisplayNameResource,
PKEY_AppUserModel_RelaunchIconResource, PKEY_FileDescription,
},
FileSystem::WIN32_FIND_DATAW,
Expand Down Expand Up @@ -504,8 +506,8 @@ impl WindowsApi {
Ok(String::from_utf16(&text[..length])?)
}

pub fn get_shell_item(path: &str) -> Result<IShellItem2> {
let wide_path: Vec<u16> = path.encode_utf16().chain(Some(0)).collect();
pub fn get_shell_item(path: &Path) -> Result<IShellItem2> {
let wide_path: Vec<u16> = path.as_os_str().encode_wide().chain(Some(0)).collect();
let item = unsafe { SHCreateItemFromParsingName(PCWSTR(wide_path.as_ptr()), None)? };
Ok(item)
}
Expand Down Expand Up @@ -534,6 +536,16 @@ impl WindowsApi {
Ok(BSTR::try_from(&value)?.to_string())
}

/// https://learn.microsoft.com/en-us/windows/win32/properties/props-system-appusermodel-relaunchdisplaynameresource
pub fn get_window_relaunch_display_name(hwnd: HWND) -> Result<String> {
let store = Self::get_property_store_for_window(hwnd)?;
let value = unsafe { store.GetValue(&PKEY_AppUserModel_RelaunchDisplayNameResource)? };
if value.is_empty() {
return Err("No AppUserModel_RelaunchDisplayName".into());
}
Ok(BSTR::try_from(&value)?.to_string())
}

/// https://learn.microsoft.com/en-us/windows/win32/properties/props-system-appusermodel-relaunchiconresource
pub fn get_window_relaunch_icon_resource(hwnd: HWND) -> Result<String> {
let store = Self::get_property_store_for_window(hwnd)?;
Expand All @@ -544,6 +556,15 @@ impl WindowsApi {
Ok(BSTR::try_from(&value)?.to_string())
}

pub fn is_uwp_package_id(package_id: &str) -> bool {
Self::get_uwp_app_info(package_id).is_ok()
}

pub fn get_uwp_app_info(umid: &str) -> Result<AppInfo> {
let app_info = AppInfo::GetFromAppUserModelId(&umid.into())?;
Ok(app_info)
}

pub fn create_temp_shortcut(program: &str, args: &str) -> Result<PathBuf> {
Com::run_with_context(|| unsafe {
let shell_link: IShellLinkW = Com::create_instance(&ShellLink)?;
Expand Down Expand Up @@ -598,22 +619,22 @@ impl WindowsApi {
Ok(out.to_string())
}

pub fn get_executable_display_name(hwnd: HWND) -> Result<String> {
let shell_item = Self::get_shell_item(&Self::exe_path(hwnd)?)?;
unsafe {
pub fn get_executable_display_name(path: &Path) -> Result<String> {
Com::run_with_context(|| unsafe {
let shell_item = Self::get_shell_item(path)?;
match shell_item.GetString(&PKEY_FileDescription) {
Ok(description) => Ok(description.to_string()?),
Err(_) => Ok(shell_item
.GetDisplayName(SIGDN_NORMALDISPLAY)?
.to_string()?
.replace(".exe", "")),
}
}
})
}

pub fn get_file_umid(path: &Path) -> Result<String> {
Com::run_with_context(|| unsafe {
let shell_item = Self::get_shell_item(&path.to_string_lossy())?;
let shell_item = Self::get_shell_item(path)?;
let store: IPropertyStore = shell_item.GetPropertyStore(GPS_DEFAULT)?;
let value = store.GetValue(&PKEY_AppUserModel_ID)?;
if value.is_empty() {
Expand Down
8 changes: 8 additions & 0 deletions src/background/windows_api/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ pub enum ProcessInformationFlag {
pub struct Process(u32);

impl Process {
pub fn from_id(id: u32) -> Self {
Self(id)
}

pub fn from_window(window: &Window) -> Self {
let (process_id, _) = WindowsApi::window_thread_process_id(window.hwnd());
Self(process_id)
Expand Down Expand Up @@ -91,4 +95,8 @@ impl Process {
}
Ok(PathBuf::from(path_string))
}

pub fn program_display_name(&self) -> Result<String> {
WindowsApi::get_executable_display_name(&self.program_path()?)
}
}
13 changes: 12 additions & 1 deletion src/background/windows_api/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,17 @@ impl Window {
WindowsApi::get_window_relaunch_command(self.0).ok()
}

/// https://learn.microsoft.com/en-us/windows/win32/properties/props-system-appusermodel-relaunchdisplaynameresource
pub fn relaunch_display_name(&self) -> Option<String> {
if let Ok(name) = WindowsApi::get_window_relaunch_display_name(self.0) {
if name.starts_with("@") {
return WindowsApi::resolve_indirect_string(&name).ok();
}
return Some(name);
}
None
}

/// https://learn.microsoft.com/en-us/windows/win32/properties/props-system-appusermodel-relaunchiconresource
pub fn relaunch_icon(&self) -> Option<String> {
WindowsApi::get_window_relaunch_icon_resource(self.0).ok()
Expand All @@ -119,7 +130,7 @@ impl Window {
if let Ok(info) = self.process().package_app_info() {
return Ok(info.DisplayInfo()?.DisplayName()?.to_string_lossy());
}
WindowsApi::get_executable_display_name(self.0)
self.process().program_display_name()
}

pub fn outer_rect(&self) -> Result<Rect> {
Expand Down

0 comments on commit 1649185

Please sign in to comment.