Skip to content

Commit f985c10

Browse files
committed
Extract mimetype packages icons
1 parent 36c2c20 commit f985c10

File tree

4 files changed

+89
-13
lines changed

4 files changed

+89
-13
lines changed

src/libappimage/desktop_integration/integrator/Integrator.cpp

Lines changed: 86 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "utils/IconHandle.h"
2525
#include "utils/path_utils.h"
2626
#include "DesktopEntryEditor.h"
27+
#include "MimeInfoEditor.h"
2728
#include "Integrator.h"
2829
#include "constants.h"
2930

@@ -50,6 +51,7 @@ namespace appimage {
5051

5152
ResourcesExtractor resourcesExtractor;
5253
DesktopEntry desktopEntry;
54+
std::map<std::string, appimage::desktop_integration::integrator::MimeInfoEditor> mimeInfoFiles;
5355

5456
Priv(const AppImage& appImage, const bf::path& xdgDataHome)
5557
: appImage(appImage), xdgDataHome(xdgDataHome),
@@ -58,17 +60,34 @@ namespace appimage {
5860
if (xdgDataHome.empty())
5961
throw DesktopIntegrationError("Invalid XDG_DATA_HOME: " + xdgDataHome.string());
6062

61-
// Extract desktop entry, DesktopIntegrationError will be throw if missing
63+
extractDesktopEntry();
64+
extractMimeInfoFiles();
65+
66+
appImageId = hashPath(appImage.getPath());
67+
}
68+
69+
/**
70+
* Extract desktop entry, DesktopIntegrationError will be throw if missing
71+
*/
72+
void extractDesktopEntry() {
6273
auto desktopEntryPath = resourcesExtractor.getDesktopEntryPath();
6374
auto desktopEntryData = resourcesExtractor.extractText(desktopEntryPath);
6475
try {
6576
desktopEntry = std::move(DesktopEntry(desktopEntryData));
6677
} catch (const DesktopEntryError& error) {
6778
throw DesktopIntegrationError(std::string("Malformed desktop entry: ") + error.what());
6879
}
80+
}
6981

70-
71-
appImageId = hashPath(appImage.getPath());
82+
/**
83+
* Extract and store mime info files to be used latter
84+
*/
85+
void extractMimeInfoFiles() {
86+
std::vector<std::string> mimeInfoPaths = resourcesExtractor.getMimeTypePackagesPaths();
87+
for (const std::string& path: mimeInfoPaths) {
88+
std::string mimeInfoFileData = resourcesExtractor.extractText(path);
89+
mimeInfoFiles.insert(std::make_pair(path, MimeInfoEditor(mimeInfoFileData)));
90+
}
7291
}
7392

7493
/**
@@ -160,6 +179,11 @@ namespace appimage {
160179
* Icons at usr/share/icons will be preferred if not available the ".DirIcon" will be used.
161180
*/
162181
void deployIcons() {
182+
deployApplicationIcon();
183+
deployMimeTypeIcons();
184+
}
185+
186+
void deployApplicationIcon() const {
163187
static const std::string dirIconPath = ".DirIcon";
164188
static const auto iconsDirPath = "usr/share/icons";
165189

@@ -177,7 +201,7 @@ namespace appimage {
177201
try {
178202
Logger::warning("Using .DirIcon as default app icon");
179203
auto dirIconData = resourcesExtractor.extract(dirIconPath);
180-
deployApplicationIcon(desktopEntryIconName, dirIconData);;
204+
deployIcon("apps", desktopEntryIconName, dirIconData);;
181205
} catch (const PayloadIteratorError& error) {
182206
Logger::error(error.what());
183207
Logger::error("No icon was generated for: " + appImage.getPath());
@@ -192,17 +216,68 @@ namespace appimage {
192216
}
193217
}
194218

219+
void deployMimeTypeIcons() {
220+
std::list<std::string> mimeTypeIconNames;
221+
for (const auto& editor : mimeInfoFiles) {
222+
auto names = editor.second.getMimeTypeIconNames();
223+
mimeTypeIconNames.merge(names);
224+
}
225+
226+
std::vector<std::string> mimeTypeIconPaths;
227+
for (const auto& iconName: mimeTypeIconNames) {
228+
auto paths = resourcesExtractor.getIconFilePaths(iconName);
229+
mimeTypeIconPaths.insert(mimeTypeIconPaths.end(), paths.begin(), paths.end());
230+
}
231+
232+
// Generate deploy paths
233+
std::map<std::string, std::string> mimeTypeIconsTargetPaths;
234+
for (const auto& path: mimeTypeIconPaths)
235+
mimeTypeIconsTargetPaths[path] = generateMimeTypeIconDeployPath(path).string();
236+
237+
resourcesExtractor.extractTo(mimeTypeIconsTargetPaths);
238+
}
239+
240+
/**
241+
* Append vendor prefix and appImage id to the file names to identify the appImage that owns
242+
* this file. Replace the default XDG_DATA_DIR by the one at <xdgDataHome>
243+
*
244+
* @param path resource path
245+
* @return path with a prefixed file name
246+
*/
247+
bf::path generateMimeTypeIconDeployPath(bf::path path) const {
248+
// add appImage resource identification prefix to the filename
249+
std::stringstream fileNameBuilder;
250+
fileNameBuilder << path.stem() << "-" << VENDOR_PREFIX << "-" << appImageId << path.extension();
251+
252+
// build the relative parent path ignoring the default XDG_DATA_DIR prefix ("usr/share")
253+
path.remove_filename();
254+
bf::path relativeParentPath;
255+
const bf::path defaultXdgDataDirPath = "usr/share";
256+
257+
for (const auto& itr : path) {
258+
relativeParentPath /= itr;
259+
260+
if (relativeParentPath == defaultXdgDataDirPath)
261+
relativeParentPath.clear();
262+
}
263+
264+
bf::path newPath = xdgDataHome / relativeParentPath / fileNameBuilder.str();
265+
return newPath;
266+
}
267+
195268
/**
196269
* Deploy <iconData> as the main application icon to
197-
* XDG_DATA_HOME/icons/hicolor/<size>/apps/<vendorPrefix>_<appImageId>_<iconName>.<format extension>
270+
* XDG_DATA_HOME/icons/hicolor/<size>/<iconGroup>/<vendorPrefix>_<appImageId>_<iconName>.<format extension>
198271
*
199-
* size: actual icon dimenzions, in case of vectorial image "scalable" is used
272+
* size: actual icon dimensions, in case of vectorial image "scalable" is used
200273
* format extension: in case of vectorial image "svg" otherwise "png"
201274
*
275+
* @param iconGroup
202276
* @param iconName
203277
* @param iconData
204278
*/
205-
void deployApplicationIcon(const std::string& iconName, std::vector<char>& iconData) const {
279+
void deployIcon(const std::string& iconGroup, const std::string& iconName,
280+
std::vector<char>& iconData) const {
206281
try {
207282
IconHandle icon(iconData);
208283

@@ -224,14 +299,14 @@ namespace appimage {
224299
iconPath /= (iconSize + "x" + iconSize);
225300
}
226301

227-
iconPath /= "apps";
302+
iconPath /= iconGroup;
228303
iconPath /= iconNameBuilder.str();
229304

230305
auto deployPath = generateDeployPath(iconPath);
231306
icon.save(deployPath.string(), icon.format());
232-
} catch (const IconHandleError& er) {
233-
Logger::error(er.what());
234-
Logger::error("No icon was generated for: " + appImage.getPath());
307+
} catch (const IconHandleError& error) {
308+
Logger::error("Icon deploy failed " + iconGroup + "/" + iconName
309+
+ " from " + appImage.getPath() + " : " + error.what());
235310
}
236311
}
237312

src/libappimage/desktop_integration/integrator/MimeInfoEditor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ namespace appimage {
5959
MimeInfoEditor::deployId = deployId;
6060
}
6161

62-
std::list<std::string> MimeInfoEditor::getMimeTypeIconNames() {
62+
std::list<std::string> MimeInfoEditor::getMimeTypeIconNames() const {
6363
std::list<std::string> icons;
6464

6565
try {

src/libappimage/desktop_integration/integrator/MimeInfoEditor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ namespace appimage {
2828

2929
std::string edit();
3030

31-
std::list<std::string> getMimeTypeIconNames();
31+
std::list<std::string> getMimeTypeIconNames() const;
3232

3333
private:
3434
boost::property_tree::ptree pt;

src/libappimage/utils/resources_extractor/ResourcesExtractor.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,5 +170,6 @@ namespace appimage {
170170

171171
throw AppImageError("Missing Desktop Entry");
172172
}
173+
173174
}
174175
}

0 commit comments

Comments
 (0)