44//! icon handling, desktop file creation, and portable directory setup.
55
66use std:: {
7+ collections:: HashSet ,
78 env,
89 ffi:: OsStr ,
910 fs:: { self , File } ,
@@ -133,14 +134,17 @@ pub fn symlink_icon_with_mode<P: AsRef<Path>>(real_path: P, system_mode: bool) -
133134
134135/// Creates a symlink for a desktop file with modified fields.
135136///
136- /// Updates the Icon, Exec, and TryExec fields in the desktop file to point
137- /// to the installed package, then creates a symlink in the applications
138- /// directory.
137+ /// Updates the Exec and TryExec fields in the desktop file to point to the
138+ /// installed package, then creates a symlink in the applications directory.
139+ /// The Icon field is rewritten to the soar-managed icon only when the package
140+ /// ships a matching icon (`has_icon`); otherwise it is left untouched so that
141+ /// references to generic system icons keep working.
139142///
140143/// # Arguments
141144///
142145/// * `real_path` - Path to the desktop file
143146/// * `package` - Package metadata
147+ /// * `has_icon` - Whether a matching soar-managed icon exists for this desktop file
144148///
145149/// # Returns
146150///
@@ -152,8 +156,9 @@ pub fn symlink_icon_with_mode<P: AsRef<Path>>(real_path: P, system_mode: bool) -
152156pub fn symlink_desktop < P : AsRef < Path > , T : PackageExt > (
153157 real_path : P ,
154158 package : & T ,
159+ has_icon : bool ,
155160) -> Result < PathBuf > {
156- symlink_desktop_with_config ( real_path, package, & get_config ( ) )
161+ symlink_desktop_with_config ( real_path, package, has_icon , & get_config ( ) )
157162}
158163
159164/// Creates a symlink for a desktop file using the provided config.
@@ -163,6 +168,7 @@ pub fn symlink_desktop<P: AsRef<Path>, T: PackageExt>(
163168pub fn symlink_desktop_with_config < P : AsRef < Path > , T : PackageExt > (
164169 real_path : P ,
165170 package : & T ,
171+ has_icon : bool ,
166172 config : & soar_config:: config:: Config ,
167173) -> Result < PathBuf > {
168174 let pkg_name = package. pkg_name ( ) ;
@@ -179,7 +185,8 @@ pub fn symlink_desktop_with_config<P: AsRef<Path>, T: PackageExt>(
179185
180186 re. replace_all ( & content, |caps : & regex:: Captures | {
181187 match & caps[ 1 ] {
182- "Icon" => format ! ( "Icon={}-soar" , file_name. to_string_lossy( ) ) ,
188+ "Icon" if has_icon => format ! ( "Icon={}-soar" , file_name. to_string_lossy( ) ) ,
189+ "Icon" => caps[ 0 ] . to_string ( ) ,
183190 "Exec" | "TryExec" => {
184191 let old_cmd = & caps[ 2 ] ;
185192 let parts: Vec < & str > = old_cmd. split_whitespace ( ) . collect ( ) ;
@@ -375,31 +382,41 @@ pub async fn integrate_package<P: AsRef<Path>, T: PackageExt>(
375382
376383 let system_mode = config. is_system ( ) ;
377384
378- let mut has_desktop = false ;
379385 let mut has_icon = false ;
386+ let mut icon_stems: HashSet < String > = HashSet :: new ( ) ;
380387 let mut symlink_action = |path : & Path | -> Result < ( ) > {
381- // Never treat the package binary itself as a desktop file. Its name can
382- // legitimately end in `.desktop`, but its contents are the executable.
383388 if path == bin_path. as_path ( ) {
384389 return Ok ( ( ) ) ;
385390 }
386391 let ext = path. extension ( ) ;
387- if ext == Some ( OsStr :: new ( "desktop" ) ) {
388- has_desktop = true ;
389- symlink_desktop_with_config ( path, package, config) ?;
392+ if ext == Some ( OsStr :: new ( "png" ) ) || ext == Some ( OsStr :: new ( "svg" ) ) {
393+ has_icon = true ;
394+ if let Some ( stem) = path. file_stem ( ) {
395+ icon_stems. insert ( stem. to_string_lossy ( ) . into_owned ( ) ) ;
396+ }
397+ symlink_icon_with_mode ( path, system_mode) ?;
390398 }
391399 Ok ( ( ) )
392400 } ;
393401 walk_dir ( install_dir, & mut symlink_action) ?;
394402
403+ let mut has_desktop = false ;
395404 let mut symlink_action = |path : & Path | -> Result < ( ) > {
405+ // Never treat the package binary itself as a desktop file. Its name can
406+ // legitimately end in `.desktop`, but its contents are the executable.
396407 if path == bin_path. as_path ( ) {
397408 return Ok ( ( ) ) ;
398409 }
399410 let ext = path. extension ( ) ;
400- if ext == Some ( OsStr :: new ( "png" ) ) || ext == Some ( OsStr :: new ( "svg" ) ) {
401- has_icon = true ;
402- symlink_icon_with_mode ( path, system_mode) ?;
411+ if ext == Some ( OsStr :: new ( "desktop" ) ) {
412+ has_desktop = true ;
413+ // Only rewrite the Icon field when this desktop file has a matching
414+ // icon shipped by the package (matched by file stem).
415+ let desktop_has_icon = path
416+ . file_stem ( )
417+ . map ( |stem| icon_stems. contains ( & * stem. to_string_lossy ( ) ) )
418+ . unwrap_or ( false ) ;
419+ symlink_desktop_with_config ( path, package, desktop_has_icon, config) ?;
403420 }
404421 Ok ( ( ) )
405422 } ;
0 commit comments