1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-23 18:25:08 +00:00

LibGUI: Generate nicer icons for symlinked files

Instead of symlinks showing up with the "filetype-symlink" icon, we now
generate a new icon by taking the target file's icon and slapping a
small arrow emblem on top of it.

This looks rather nice. :^)
This commit is contained in:
Andreas Kling 2020-12-16 11:53:48 +01:00
parent 3d5e30a1e6
commit c44dbabda1
3 changed files with 38 additions and 2 deletions

View file

@ -24,11 +24,14 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <AK/LexicalPath.h>
#include <AK/String.h>
#include <LibCore/ConfigFile.h>
#include <LibCore/File.h>
#include <LibCore/StandardPaths.h>
#include <LibGUI/FileIconProvider.h>
#include <LibGUI/Icon.h>
#include <LibGUI/Painter.h>
#include <LibGfx/Bitmap.h>
#include <sys/stat.h>
@ -45,6 +48,8 @@ static Icon s_symlink_icon;
static Icon s_socket_icon;
static Icon s_executable_icon;
static Icon s_filetype_image_icon;
static RefPtr<Gfx::Bitmap> s_symlink_emblem;
static RefPtr<Gfx::Bitmap> s_symlink_emblem_small;
static HashMap<String, Icon> s_filetype_icons;
static HashMap<String, Vector<String>> s_filetype_patterns;
@ -57,6 +62,9 @@ static void initialize_if_needed()
auto config = Core::ConfigFile::open("/etc/FileIconProvider.ini");
s_symlink_emblem = Gfx::Bitmap::load_from_file("/res/icons/symlink-emblem.png");
s_symlink_emblem_small = Gfx::Bitmap::load_from_file("/res/icons/symlink-emblem-small.png");
s_hard_disk_icon = Icon::default_icon("hard-disk");
s_directory_icon = Icon::default_icon("filetype-folder");
s_directory_open_icon = Icon::default_icon("filetype-folder-open");
@ -127,8 +135,36 @@ Icon FileIconProvider::icon_for_path(const String& path, mode_t mode)
return s_inaccessible_directory_icon;
return s_directory_icon;
}
if (S_ISLNK(mode))
return s_symlink_icon;
if (S_ISLNK(mode)) {
auto raw_symlink_target = Core::File::read_link(path);
if (raw_symlink_target.is_null())
return s_symlink_icon;
String target_path;
if (raw_symlink_target.starts_with('/')) {
target_path = raw_symlink_target;
} else {
target_path = Core::File::real_path_for(String::formatted("{}/{}", LexicalPath(path).dirname(), raw_symlink_target));
}
auto target_icon = icon_for_path(target_path);
Icon generated_icon;
for (auto size : target_icon.sizes()) {
auto& emblem = size < 32 ? *s_symlink_emblem_small : *s_symlink_emblem;
auto original_bitmap = target_icon.bitmap_for_size(size);
ASSERT(original_bitmap);
auto generated_bitmap = original_bitmap->clone();
if (!generated_bitmap) {
dbgln("Failed to clone {}x{} icon for symlink variant", size, size);
return s_symlink_icon;
}
GUI::Painter painter(*generated_bitmap);
painter.blit({ size - emblem.width(), size - emblem.height() }, emblem, emblem.rect());
generated_icon.set_bitmap_for_size(size, move(generated_bitmap));
}
return generated_icon;
}
if (S_ISSOCK(mode))
return s_socket_icon;
if (mode & (S_IXUSR | S_IXGRP | S_IXOTH))