cerebroapp / cerebro

🔵 Cerebro is an open-source launcher to improve your productivity and efficiency
https://www.cerebroapp.com/
MIT License
8.32k stars 455 forks source link

Get file icon on Linux #17

Closed KELiON closed 2 years ago

KELiON commented 7 years ago

Find a way to read file icon on Linux

maximbaz commented 7 years ago

I investigated this a bit, the algorithm looks like this:

  1. Determine the file's MIME type.

Found a simple way here: Execute in shell: gvfs-info -a standard::icon /full/path/to/file.txt Output:

uri: file:///full/path/to/file.txt
attributes:
  standard::icon: text-plain, text-x-generic

The last line defines matching MIME types, in the order of priority.

  1. Find an icon for the corresponding MIME type.

The search would be /usr/share/icons/**/text-plain.*, if not found then /usr/share/icons/**/text-x-generic.* (popular ones are png and svg files). If nothing matches, then just choose some default a use it. On my machine nothing matches for text-plain, but there are a few results for text-x-generic, in different theme folders. How to know which theme to use?

  1. Determine a theme to use.

~Found this command here:~

~gsettings get org.gnome.desktop.interface gtk-theme~

@bil-elmoussaoui suggests a better command:

gsettings get org.gnome.desktop.interface icon-theme

Plus this will only work on Gnome and derivatives, so for example on Cinnamon the command would be:

gsettings get org.cinnamon.desktop.interface icon-theme

It is unclear yet what are the commands that will work on other desktop environments.

It outputs a theme name for me: Adwaita

Therefore the search should be prioritized for /usr/share/icons/Adwaita/**/text-x-generic.*, if not found then consider all the other folders.

  1. Determine a resolution to use.

Same rules as with icon resolutions for the apps.


Therefore, for my example with a text file, the correct icon to use is located at:

/usr/share/icons/Adwaita/256x256/mimetypes/text-x-generic.png

I wish it was simpler.

maximbaz commented 7 years ago

We could also use this algorithm to show default application icons, in case we didn't find any icon for the application itself. Default icon is better than no icon.

bilelmoussaoui commented 7 years ago

@maximbaz you shouldn't be looking at gtk-theme but icon-theme instead. + This will only work on a gnome desktop or a derivate of it, it won't work on cinnamon for example as they use org.cinnamon.desktop.interface instead.

maximbaz commented 7 years ago

Thanks! updated the message.

bilelmoussaoui commented 7 years ago

@KELiON Hey! How can I get in touch with you about this issue? I'm currently trying to implement a simple way to find an icon on the theme. For now, the whole code is Sync (i will implement an Async version once everything works as expected).

The whole package is just one file and pretty easy to use. It has one function which is getIcon() It takes three parameters: The icon name, the icon size, and the context of the icon (mime types here in your issue). What is good about what I've done till now, is that the code handles themes inherited without any issue. If you're using theme X and it's inherited theme Y, if you look for a Z icon and it's not found on X, the code will look on Y after that.

But as I'm not that good JS dev, I don't know how should i handle the case where the iconPath (found by the getIcon) is an SVG icon instead of a png one?

For now, I'm thinking of converting the SVG icon to a png one and returning the buffer, this way it can be easily used using nativeImage.createFromBuffer. But i couldn't find any great package to handle svg to png conversions.

I tried my solution with a simple electron app with a tray icon, and the code I wrote works well and get the correct icon to work.

If you would like, we can get this done together (just a few tips and code review/improvements from you) and this can be used across all other electron applications. Either for using a themeable tray icon (which is requested in every icon theme out there) or for some cases like your application! Thanks and keep up the great work!

maximbaz commented 7 years ago

Is it not possible to render SVG icon? Why do you want to convert it to PNG? I'm asking because we use SVG icons for app icons, for example, without any conversion.

bilelmoussaoui commented 7 years ago

@maximbaz sadly, tray icons on electron can not use SVG icons.... The reason why i wanted to convert it to png's is to be able to return a base64 encoded png to be used with nativeImage.createfromBuffer. Anyway, I've already figured out how to handle all of that! You can now either get the Buffer or the absolute path of the image:+1:

bilelmoussaoui commented 7 years ago

Here you go : https://github.com/bil-elmoussaoui/linux-icons

maximbaz commented 7 years ago

Nice job @bil-elmoussaoui! Am I right to assume that your project can be used not only for file icons, but also for application icons (https://github.com/KELiON/cerebro/issues/97) ?

bilelmoussaoui commented 7 years ago

@maximbaz The difference between app icons and mime types is the context (the third parameter you use). If you want to get an application icon you would do

const icons = require('linux-icons')
icons.getIcon('myicon-name', 22, icons.Context.APPLICATION, iconPath => {
  console.log(iconPath)
})

Here's the list of supported Contexts (the free desktop standards https://github.com/bil-elmoussaoui/linux-icons/blob/master/index.js#L26) which will work on every Linux distro out there!

maximbaz commented 7 years ago

Cool! That would be a great improvement to use your new library for both app and file icons 👍

Consider getting this integrated in Cerebro, many people will be thankful 😜 I can help out with testing or reviewing the code.

Just keep in mind, the functionality was recently extracted in separate plugins: cerebro-basic-apps and cerebro-files-nav

bilelmoussaoui commented 7 years ago

@maximbaz That would be awesome, as a JS noob my code isn't perfect and it can be improved a lot. Especially the fact that I'm using svg2png to convert SVG icons to png's, this library uses PhantomJS which is not that good (huge library as dependency...);

ogustavo-pereira commented 3 years ago

Try to use this https://gist.github.com/PurpleBabar/b7ab56435a172b743a8f5f3b255c4cb3

@PurpleBabar

blueray453 commented 1 year ago

Please try:

#!/usr/bin/env gjs

const { Gio } = imports.gi;

let file = Gio.File.new_for_path(ARGV[0]);
let fileInfo = file.query_info('*', Gio.FileQueryInfoFlags.NONE, null);
let icons = fileInfo.get_icon().get_names();

print(icons[0]);

You have to send the file path in double quote as argument to this script.