The officially official Devuan Forum!

You are not logged in.

#1 Yesterday 22:19:02

Eeqmcsq
Member
Registered: 2017-09-19
Posts: 69  

[How to] Excalibur + Xfce: Update the icon themes for Xfce's rDNS file

* Intro

After a fresh Excalibur + Xfce install, I tried changing the icon theme to Tango (Applications -> Settings -> Appearance). I noticed that the application icons along the bottom panel didn't change. In fact the only theme that showed any changes was the Deepsea theme.

From my research, in Xfce 4.16, they changed the code to look for rDNS (reverse DNS) icon file names. Example, for the "Show Desktop" icon, Xfce previously looked for "user-desktop.png". In 4.16, the code now looks for "org.xfce.panel.showdesktop.png".

Some solutions online says that you can update the icon theme by creating a symbolic link with the new rDNS file name and point it to the original file. But an icon theme has icons for multiple sizes (16x16, 24x24, etc). So it would be very tedious to manually add all of these symlinks for all of these sizes.

I wrote a Perl script that contains these file name mappings, and it will create a symlink if the new file name doesn't exist and if the old file name exists. I tested it on several of the Xfce icon themes, and it seems to work correctly, so I'm sharing the script with instructions.

By the way, the reason why the Deepsea theme changed was that some people from Devuan went to the Xfce forums and posted some questions about the icons. So they added a few symlinks with the rDNS file names to the Deepsea theme, which is why that theme showed a difference.

* Old to new icon file name mappings
         
Excalibur's Xfce is version 4.20. But I couldn't find any definitive list of icon file name mappings. The best I could do was to start with the file name mappings published for 4.16:

  https://wiki.xfce.org/releng/4.16/icons … _for_icons

and include extra entries found in a user's script:

  https://gist.github.com/bluesabre/582d8 … 81df9b2a3c

* Instructions

This example will update the Tango icon theme.

- Copy the code in the next comment into a perl script file. Example: /tmp/fix_xfce_icon_names.pl

- Make the file executable.

chmod +x /tmp/fix_xfce_icon_names.pl

- Create an icons directory in your home directory if it doesn't exist, then go into it.

mkdir -p ~/.local/share/icons
cd ~/.local/share/icons

- Inside your local icons directory, copy the Tango icon theme to this directory. This example will use a different directory name, so you can tell that this is the modified theme. The "-a" is the "archive" mode, which tries to preserve all of the file properties, so you can tell which files were the original files by the modified date if needed.

cp -a /usr/share/icons/Tango Tango2

- Staying in your local icons directory, run the icon update script on Tango2.

/tmp/fix_xfce_icon_names.pl Tango2

- Recommended: Update the display name for Tango2, so you can tell the difference from the original Tango theme in Xfce's Appearance app.

mousepad Tango2/index.theme

  Change the "Name=" to "Tango2" and the "Comment=" to include Tango2.

- Launch a new instance of the Appearance app.

    Applications -> Settings -> Appearance -> Icons tab

  You can now switch between Tango and Tango2 and see the updated icon names taking effect.

- If anything goes wrong, you can delete your local Tango2 and start again.

- Also, I recommend saving the perl script to a more permanent location so you can run it again if you want to use a different icon theme.

Offline

#2 Yesterday 22:20:03

Eeqmcsq
Member
Registered: 2017-09-19
Posts: 69  

Re: [How to] Excalibur + Xfce: Update the icon themes for Xfce's rDNS file

My perl script

2025.10.19: Posted the first version of the script to update the icons theme for Xfce's rDNS file names.

#!/usr/bin/perl -W

use strict  ;
use warnings;
use Cwd     ;
use constant false => 0;
use constant true  => 1;

#In Xfce 4.16, the code switched to use rDNS (reverse DNS) icon file names. Example: The file name that Xfce expects
#for showing the desktop was changed from "user-desktop.png" to "org.xfce.panel.showdesktop.png". See:
#  https://wiki.xfce.org/releng/4.16/icons_rdns_naming_for_icons
#
#In Devuan Excalibur, most of the icon themes have NOT been updated to include the rDNS files, so the theme's icons
#are not loaded.
#
#This script will take in an icon directory and add symbolic links using Xfce's new rDNS file names to the old file names
#currently in the icon theme. The symlinks are created only if the symlink doesn't exist AND if the old file name
#exists.

######## VARIABLES ########

my $gstrIconDir = "";   #The user specified directory to an icon theme. The directory must contain the file icon-theme.cache.

#A hash of Xfce's new rDNS (reverse DNS) icon file names to the old file names.
#The table came from 2 sources:
#  - Xfce's official list from 4.16.
#    https://wiki.xfce.org/releng/4.16/icons_rdns_naming_for_icons
#  - A user's script, which contains a few more entries than the original table.
#    https://gist.github.com/bluesabre/582d886a02c793285f4e3081df9b2a3c
#  * Notes
#    - In Xfce's list, the new "xfsm-hibernate" maps to two old files: "system-hibernate", "system-suspend-hibernate".
#      In the user's script, that's mapped to only "system-suspend-hibernate".
#      - I decided to support both, with "system-hibernate" as the first choice, since that more closely matches the new name.
#    - In Xfce's list, the old "preferences-desktop-default-applications" is mapped to the new
#      "org.xfce.settings.preferred-application". But in the user's script, it's mapped to "org.xfce.settings.default-applications".
#      - I decided to map it to "preferences-desktop-default-applications", because I see it in the Xfce changelog for 4.18.
#
#For new icons that refer to multiple old file names, I used a | to separate the old file names.
my %hashXfceNewtoOldFileNames =
(
    "org.xfce.about"       => "help-about"         ,
    "org.xfce.appfinder"   => "edit-find"          ,
    "org.xfce.catfish"     => "catfish"            ,
    "org.xfce.Dictionary"  => "xfce4-dict"         ,
    "org.xfce.filemanager" => "system-file-manager",

    "org.xfce.genmon"       => "utilities-system-monitor",
    "org.xfce.gigolo"       => "gtk-network"             ,
    "org.xfce.mailreader"   => "emblem-mail"             ,
    "org.xfce.mousepad"     => "accessories-text-editor" ,
    "org.xfce.notification" => "xfce4-notifyd"           ,

    "org.xfce.panel"                  => "xfce4-panel"               ,
    "org.xfce.panel.actions"          => "system-log-out"            ,
    "org.xfce.panel.applicationsmenu" => "xfce4-panel-menu"          ,
    "org.xfce.panel.clock"            => "x-office-calendar"         ,
    "org.xfce.panel.directorymenu"    => "folder"                    ,
    "org.xfce.panel.launcher"         => "application-x-executable"  ,
    "org.xfce.panel.pager"            => "xfce4-workspaces"          ,
    "org.xfce.panel.separator"        => "list-remove-symbolic"      ,
    "org.xfce.panel.showdesktop"      => "user-desktop"              ,
    "org.xfce.panel.tasklist"         => "preferences-system-windows",
    "org.xfce.panel.windowmenu"       => "preferences-system-windows",

    "org.xfce.parole"        => "parole"                         ,
    "org.xfce.powermanager"  => "xfce4-power-manager-settings"   ,
    "org.xfce.ristretto"     => "ristretto"                      ,
    "org.xfce.ScreenSaver"   => "preferences-desktop-screensaver",
    "org.xfce.screenshooter" => "applets-screenshooter"          ,
    "org.xfce.session"       => "xfce4-session"                  ,

    "org.xfce.settings.accessibility"        => "preferences-desktop-accessibility"       ,
    "org.xfce.settings.appearance"           => "preferences-desktop-theme"               ,
    "org.xfce.settings.color"                => "xfce4-color-settings"                    ,
    "org.xfce.settings.default-applications" => "preferences-desktop-default-applications",
    "org.xfce.settings.display"              => "video-display"                           ,
    "org.xfce.settings.editor"               => "preferences-system"                      ,
    "org.xfce.settings.keyboard"             => "preferences-desktop-keyboard"            ,
    "org.xfce.settings.manager"              => "preferences-desktop"                     ,
    "org.xfce.settings.mouse"                => "preferences-desktop-peripherals"         ,

    "org.xfce.taskmanager"       => "utilities-system-monitor",
    "org.xfce.terminal-settings" => "utilities-terminal"      ,
    "org.xfce.terminal"          => "utilities-terminal"      ,
    "org.xfce.terminalemulator"  => "utilities-terminal"      ,
    "org.xfce.thunar"            => "Thunar"                  ,

    "org.xfce.volman"      => "drive-removable-media",
    "org.xfce.webbrowser"  => "web-browser"          ,
    "org.xfce.workspaces"  => "xfce4-workspaces"     ,
    "org.xfce.xfburn"      => "xfburn"               ,
    "org.xfce.xfdashboard" => "xfdashboard"          ,

    "org.xfce.xfdesktop"    => "preferences-desktop-wallpaper",
    "org.xfce.xfmpc"        => "multimedia-player"            ,
    "org.xfce.xfwm4-tweaks" => "wmtweaks"                     ,
    "org.xfce.xfwm4"        => "xfwm4"                        ,

    "xfsm-hibernate"   => "system-hibernate|system-suspend-hibernate",
    "xfsm-lock"        => "system-lock-screen",
    "xfsm-logout"      => "system-log-out"    ,
    "xfsm-reboot"      => "system-reboot"     ,
    "xfsm-shutdown"    => "system-shutdown"   ,
    "xfsm-suspend"     => "system-suspend"    ,
    "xfsm-switch-user" => "system-users"      ,
);

######## FUNCTIONS ########

#Perform cleanup before the script exits with the given exit code.
#
#$_[0] [in] - Optional - The exit code to exit the script with. Default = 0.
sub CleanupExit
{
    my $iExitCode = @_ >= 1 ? $_[0] : 0;

    #Insert extra cleanup here before the script exits.

    exit($iExitCode);
}

#Args: none
#Return: 0
sub PrintHelp
{
    printf("Usage: The first arg must be a directory of an icon theme. The directory must contain\n");
    printf("the file \"icon-theme.cache\".\n");

    return 0;
}

#Parses @ARGV for the path to the icon theme.
#
#Args: none
#
#Return: 0 on success, 1 on failure.
sub ParseArgv
{
    if (scalar(@ARGV) < 1)
    {
        PrintHelp();
        return 1;
    }
    
    my $strIconDir = $ARGV[0];
    
    if (! -e "$strIconDir")
    {
        printf("!!! Error: Directory does not exist: %s\n", $strIconDir);
        return 1;
    }

    if (! -d "$strIconDir")
    {
        printf("!!! Error: Specified path is not a directory: %s\n", $strIconDir);
        return 1;
    }
    
    my $strIconCacheFile = "$strIconDir/icon-theme.cache";

    if (! -e "$strIconCacheFile")
    {
        printf("!!! Error: The file \"icon-theme.cache\" was not found in the directory: %s\n", $strIconDir);
        return 1;
    }

    if (! -f "$strIconCacheFile")
    {
        printf("!!! Error: The \"icon-theme.cache\" in the directory \"%s\" is not a plain file.\n", $strIconDir);
        return 1;
    }

    $gstrIconDir = $strIconDir;

    return 0;
}

#Check that the required cmds or apps are found on the path.
#
#Args: none
#
#Return: 0 on success, 1 on failure.
sub CheckRequiredCmds
{
    if (system("which gtk-update-icon-cache > /dev/null") != 0)
    {
        printf("!!! Error: The cmd \"gtk-update-icon-cache\" was not found. This is needed to update the theme's icon cache file.\n");
        return 1;
    }

    return 0;
}

#Helper function to read the directory entries into an array, ignoring the special directories "." and "..".
#
#Args:
#  $_[0] - String of the directory name to open.
#  $_[1] - A reference to an array to receive the directory entry strings.
#
#Return: 0 on success, 1 on failure.
sub ReadDirEntriesIgnoreSpDirs
{
    my $strDir             = $_[0];
    my $refarstrDirEntries = $_[1];
    
    my $hDIR;
    
    @$refarstrDirEntries = ();

    #Open the current directory and read all of the directory entries into an array.
    if (!opendir($hDIR, $strDir))
    {
        printf("!!! Could not open the directory to get the subdirectories: %s\n", $strDir);
        return 1;
    }
    my @arstrDirEntries = readdir($hDIR);
    closedir($hDIR);

    #Ignore the special directories "." and "..". grep keeps the elements where the block function returns true.
    #$_ refers to each element in the array.
    @$refarstrDirEntries = grep { $_ ne "." && $_ ne ".." } @arstrDirEntries;

    return 0;
}

#Create symbolic links of the new Xfce icon names to the old file name. The symlinks are created only if the symlink
#doesn't exist AND if the old file name exists.
#
#Args: none
#
#Return: 0 on success, 1 on failure.
sub CreateNewXfceIconNames
{
    my $iRet = 1, my $iNumCreated = 0;
    my $hICONDIR, my $hSIZEDIR, my $hCATEGORYDIR;

    my @arNewFileNameKeys = keys(%hashXfceNewtoOldFileNames);

    #Supported file extensions for the icon file names.
    my @arFileExt = ( ".png", ".svg" );

    #Read all of the icon theme directory's entries, which should contain size subdirectories and other files.
    my @arstrIconDirEntries;
    if (ReadDirEntriesIgnoreSpDirs($gstrIconDir, \@arstrIconDirEntries) != 0)
        { goto CLEANUPRETURN; }

    #Sort all of the arrays, so the printed output is more organized and easier for the user to see what symlinks
    #were created.
    @arNewFileNameKeys   = sort(@arNewFileNameKeys  );
    @arstrIconDirEntries = sort(@arstrIconDirEntries);

    foreach my $strIconDirEntry (@arstrIconDirEntries)
    {
        #Skip anything that's not a subdirectory.
        if (! -d "$gstrIconDir/$strIconDirEntry")
            { next; }

        #We're have a subdirectory name of the icon theme directory that represents the icon size.
        #Example: 16x16, 22x22, scalable, etc.
        my $strThisSizeDir = "$gstrIconDir/$strIconDirEntry";

        #Read all of the size directory's entries, which should contain category subdirectories.
        my @arstrSizeDirEntries;
        if (ReadDirEntriesIgnoreSpDirs($strThisSizeDir, \@arstrSizeDirEntries))
            { goto CLEANUPRETURN; }

        @arstrSizeDirEntries = sort(@arstrSizeDirEntries);

        foreach my $strSizeDirEntry (@arstrSizeDirEntries)
        {
            #Skip anything that's not a subdirectory.
            if (! -d "$strThisSizeDir/$strSizeDirEntry")
                { next; }

            #We're have a subdirectory name of the size directory that represents the category.
            #Example: actions, apps, places, etc.
            my $strThisCategoryDir = "$strThisSizeDir/$strSizeDirEntry";

            #Read all of the category directory's entries, which should contain the theme icon files.
            my @arstrCategoryDirEntries;
            if (ReadDirEntriesIgnoreSpDirs($strThisCategoryDir, \@arstrCategoryDirEntries))
                { goto CLEANUPRETURN; }

            #Inside the category directory, we should have .png or .svg files that are the old icon files.
            #They may also include new icon files if this icon theme has already been updated with the new
            #Xfce rDNS file names. Also, some of these entries might be symbolic links to other files.
            
            #Check each new file to old file mapping. If the old file is here, and the new file is NOT here,
            #create a symbolic link. Check for both .png and .svg file extensions.
            foreach my $strThisNewFileName (@arNewFileNameKeys)
            {
                #Since a new file may contain multiple old files, we separate the old file string by the | to get
                #each old file name. We'll use the first matching old file.
                #Example: "xfsm-hibernate" => "system-hibernate|system-suspend-hibernate"
                my @arstrOldFileNames = split(/\|/, $hashXfceNewtoOldFileNames{$strThisNewFileName});
                
                #Check each of the supported file extensions. Example: .png, .svg.
                foreach my $strThisFileExt (@arFileExt)
                {
                    foreach my $strThisOldFileName (@arstrOldFileNames)
                    {
                        my $strThisOldFileNameExt = $strThisOldFileName . $strThisFileExt;
                        my $strThisNewFileNameExt = $strThisNewFileName . $strThisFileExt;
    
                        if (-e "$strThisCategoryDir/$strThisNewFileNameExt")
                            { next; }  #This new icon file has already been created.
                        
                        #This new icon file hasn't been created. Check if the old icon file exists in this category directory.
                        #$_ refers to each element in the array.
                        my @grepRet = grep { $_ eq $strThisOldFileNameExt } @arstrCategoryDirEntries;
                        if (scalar(@grepRet) == 0)
                            { next; }  #The old icon file wasn't found in this directory. Can't make a symlink.

                        #Construct the command to create the new file symbolic link to the old file. Reminder
                        #that the new symlink is supposed to be in the same directory as the old file. But we're not
                        #inside this category directory. So the symlink command will contain just the old file name
                        #as the "target", and the "link name" will be a path to where the symlink will be created.
                        #Example:
                        #  ln -sv "user-desktop.png" "Tango/32x32/places/org.xfce.panel.showdesktop.png"
                        #
                        #  -s : create symbolic link
                        #  -v : print name of each linked file
                        my $strCmd = sprintf("ln -sv \"%s\" \"%s/%s\"", $strThisOldFileNameExt, $strThisCategoryDir, $strThisNewFileNameExt);
                        if (system($strCmd) != 0)
                            { goto CLEANUPRETURN; }
                        
                        #We've created a new icon file name symlink to one of the old files. Skip any other old file names.
                        $iNumCreated++;
                        last;
                    }
                }
                #we're done with this new icon file name.
            }
            #We're done with this category subdirectory.
        }
        #We're done with this size subdirectory.
    }

    if ($iNumCreated > 0)
    {
        printf("\n");
        printf("* Updating the theme's \"icon-theme.cache\" so it knows about the new files.\n");
        my $strCmd = sprintf("gtk-update-icon-cache \"%s\"", $gstrIconDir);
        if (system($strCmd) != 0)
            { goto CLEANUPRETURN; }
    }
    else
    {
        printf("* No new files were created. Skipping updating the theme's \"icon-theme.cache\".\n");
    }
    
    #We've successfully updated the icon theme directory.
    $iRet = 0;
    
CLEANUPRETURN:

    return $iRet;
}

######## BEGIN SCRIPT ########

ParseArgv             () == 0 || CleanupExit(1);
CheckRequiredCmds     () == 0 || CleanupExit(1);
CreateNewXfceIconNames() == 0 || CleanupExit(1);

CleanupExit 0;

######## END SCRIPT ########

Offline

Board footer