24
24
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
25
*/
26
26
27
+ #include < AK/LexicalPath.h>
27
28
#include < AK/String.h>
28
29
#include < LibCore/ConfigFile.h>
30
+ #include < LibCore/File.h>
29
31
#include < LibCore/StandardPaths.h>
30
32
#include < LibGUI/FileIconProvider.h>
31
33
#include < LibGUI/Icon.h>
34
+ #include < LibGUI/Painter.h>
32
35
#include < LibGfx/Bitmap.h>
33
36
#include < sys/stat.h>
34
37
@@ -45,6 +48,8 @@ static Icon s_symlink_icon;
45
48
static Icon s_socket_icon;
46
49
static Icon s_executable_icon;
47
50
static Icon s_filetype_image_icon;
51
+ static RefPtr<Gfx::Bitmap> s_symlink_emblem;
52
+ static RefPtr<Gfx::Bitmap> s_symlink_emblem_small;
48
53
49
54
static HashMap<String, Icon> s_filetype_icons;
50
55
static HashMap<String, Vector<String>> s_filetype_patterns;
@@ -57,6 +62,9 @@ static void initialize_if_needed()
57
62
58
63
auto config = Core::ConfigFile::open (" /etc/FileIconProvider.ini" );
59
64
65
+ s_symlink_emblem = Gfx::Bitmap::load_from_file (" /res/icons/symlink-emblem.png" );
66
+ s_symlink_emblem_small = Gfx::Bitmap::load_from_file (" /res/icons/symlink-emblem-small.png" );
67
+
60
68
s_hard_disk_icon = Icon::default_icon (" hard-disk" );
61
69
s_directory_icon = Icon::default_icon (" filetype-folder" );
62
70
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)
127
135
return s_inaccessible_directory_icon;
128
136
return s_directory_icon;
129
137
}
130
- if (S_ISLNK (mode))
131
- return s_symlink_icon;
138
+ if (S_ISLNK (mode)) {
139
+ auto raw_symlink_target = Core::File::read_link (path);
140
+ if (raw_symlink_target.is_null ())
141
+ return s_symlink_icon;
142
+
143
+ String target_path;
144
+ if (raw_symlink_target.starts_with (' /' )) {
145
+ target_path = raw_symlink_target;
146
+ } else {
147
+ target_path = Core::File::real_path_for (String::formatted (" {}/{}" , LexicalPath (path).dirname (), raw_symlink_target));
148
+ }
149
+ auto target_icon = icon_for_path (target_path);
150
+
151
+ Icon generated_icon;
152
+ for (auto size : target_icon.sizes ()) {
153
+ auto & emblem = size < 32 ? *s_symlink_emblem_small : *s_symlink_emblem;
154
+ auto original_bitmap = target_icon.bitmap_for_size (size);
155
+ ASSERT (original_bitmap);
156
+ auto generated_bitmap = original_bitmap->clone ();
157
+ if (!generated_bitmap) {
158
+ dbgln (" Failed to clone {}x{} icon for symlink variant" , size, size);
159
+ return s_symlink_icon;
160
+ }
161
+ GUI::Painter painter (*generated_bitmap);
162
+ painter.blit ({ size - emblem.width (), size - emblem.height () }, emblem, emblem.rect ());
163
+
164
+ generated_icon.set_bitmap_for_size (size, move (generated_bitmap));
165
+ }
166
+ return generated_icon;
167
+ }
132
168
if (S_ISSOCK (mode))
133
169
return s_socket_icon;
134
170
if (mode & (S_IXUSR | S_IXGRP | S_IXOTH))
0 commit comments