AppImageCommunity / appimaged

appimaged is a daemon that monitors the system and integrates AppImages.
https://appimage.org
Other
296 stars 16 forks source link

[appimaged] In KDE Plasma, icons are not shown in the menu #37

Open probonopd opened 7 years ago

probonopd commented 7 years ago

The Icon Theme Specification actually does not specify $XDG_DATA_HOME as a source for icons, hence applications in userspace do not have a standard way to place their icons. Although Ubuntu Unity, XFCE, and other desktops do pick icons up from there, but KDE Plasma doesn't.

https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html

@ximion, am I reading the XDG spec correctly, and do you think we should propose a change? https://bugreports.qt.io/browse/QTBUG-48417

This seems to be a 12-year old issue: https://lists.freedesktop.org/archives/xdg/2004-September/003280.html

In the KDE Plasma GUI there is no notion of per-user icons either: http://askubuntu.com/questions/788386/how-to-add-icons-on-the-kde-menu-editor-icon-source

In addition, KDE Plasma seems to ignore icons in $HOME/.icons.

Effectively leaving no way for an user-space application like appimaged to install icons for applications.

ximion commented 7 years ago

Are you sure? Icons are searched in XDG_DATA_DIRS, there is no DATA_HOME currently in use to my knowledge. And since the home directory is in the default list of XDG paths, dropping an icon into ~/.local/share/icons/hicolor/<size>/apps/ will just work. I am not aware of any desktop which doesn't implement that, and it definitely works on both GNOME and KDE.

probonopd commented 7 years ago

Are you sure?

Tested with kubuntu-16.04-desktop-amd64.iso and neon-useredition-20160901-1018-amd64.iso, I get consistent, reproducible behavior:

The results are:

So @ximion how do you read the spec, is KDE Plasma spec compliant or is it violating the spec?

The default ENV is:

$ env | grep XDG
XDG_VTNR=7
XDG_SESSION_ID=3
XDG_SESSION_CLASS=user
XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session2
XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0
XDG_CONFIG_DIRS=/etc/xdg/xdg-/usr/share/xsessions/plasma:/etc/xdg:/usr/share/kubuntu-default-settings/kf5-settings
XDG_SESSION_TYPE=x11
XDG_SEAT=seat0
XDG_SESSION_DESKTOP=KDE
XDG_DATA_DIRS=/usr/share//usr/share/xsessions/plasma:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop
XDG_RUNTIME_DIR=/run/user/999
XDG_CURRENT_DESKTOP=KDE

An a workaround, I can put in the absolute path as the value for the Icon= key for now but I would like to avoid that if possible.

ximion commented 7 years ago

Yeah, but .icons is a non-standard path almost nobody supports. Put your icons into ~/.local/share/icons/hicolor/<size>/apps/ which is the canonical location. If the icons don't show up, the XDG_DATA_DIRS variable would need another entry for the current user (easy enough to set, Flatpak sets a custom location too).

probonopd commented 7 years ago

@ximion thanks, ~/.local/share/icons/hicolor/<size>/apps/ would work of course, but what do I do for icons which I don't know the size for? (e.g., stuff coming from usr/share/pixmaps)?

ximion commented 7 years ago

@probonopd I would not support them - share/pixmaps is bad for various reasons. If you do want some level of support, you could determine the size of the images and then place them correctly named in the right directory.

probonopd commented 7 years ago

Sigh. it works everywhere but KDE...

ximion commented 7 years ago

$HOME/.icons is legacy and should die. Use $XDG_DATA_DIRS/icons (~/.local/share/icons/hicolor/<size>/apps/) and you should be fine. The latter works everywhere and is what everyone, including proprietary stuff, uses.

probonopd commented 7 years ago

Looks like /home/me/.local/share/icons/hicolor/scalable/apps/appimagekit_f9178380f3005f0de7f4ca115e454e9e_openscad.png is not recognized in Ubuntu but copying it to /home/me/.local/share/icons/ does the trick for Ubuntu :-/ Why can't all distros just agree on one place where to put icons of which I don't know the size, or are in a non-standard size.

ximion commented 7 years ago

@probonopd The ~/.local/share/icons/hicolor directory is the standard - you just need to use it correctly. Putting .png (= pixmaps, non-scalable) icons into scalable/apps is not okay (it can work, but there are no guarantees). See /usr/share/icons/hicolor/index.theme on how the directories are defined. Further information can be found in the XDG icon theme spec.

So, determine the size of the pixmap and place it in ~/.local/share/icons/hicolor/<size>/apps/<pixmap>.png and you should be fine. Of course, the .desktop file's icon name must contain the icon name (without .svg/.png suffix!) in its Icon= entry.

The system needs to know the size without opening up the icon file for speed reasons, and we need the different sizes to provide UIs which scale on different form factors and display sizes as well as different places (e.g. menus vs desktop-icons). There is no way around doing it right ;-) Just determine the icon size at appimage build or install time and do the right thing (also ensure that the icon size falls into one of the icon sizes supported by the hicolor theme). Or make people provide an svg icon and put it into the scalable location.

probonopd commented 7 years ago

OK, so it looks like I really have to parse the images and determine their size. One way to do this is

// sudo apt install libcairo-dev
// gcc getsize.c -I/usr/include/cairo/ -lcairo  -o getsize
// or 
// gcc getsize.c $(pkg-config --libs --cflags cairo) -o getsize

#include <cairo.h>
#include <stdio.h>

int main (int argc, char *argv[])
{
        cairo_surface_t *image;
        image = cairo_image_surface_create_from_png(argv[1]);
        int w = cairo_image_surface_get_width (image);
        int h = cairo_image_surface_get_height (image);
        fprintf(stderr, "w = %i\n", w); 
        fprintf(stderr, "h = %i\n", h); 
        cairo_surface_destroy (image);
        return 0;
}

But now the question arises, what do I do with icons that do not fit into the usual suspect sizes like 48x48, 64x64, 128x128, and so on.

$ ./getsize /home/me/.icons/appimagekit_99af24415f947efc83d8203d60a92c2e_graphmonkey.png 
w = 61
h = 52

Do I really have to resize them first in order for the desktop environment to be able to display them?

Also, can I be sure to find these sizes on every system?

$ ls /usr/share/icons/hicolor/
1024x1024  22x22    42x42    8x8               symbolic
128x128    24x24    48x48    96x96
16x16      256x256  512x512  icon-theme.cache
192x192    32x32    64x64    index.theme
20x20      36x36    72x72    scalable

grep apps /usr/share/icons/hicolor/index.theme | grep x | cut -d x -f 1 | cut -d "[" -f 2 | sort -n | uniq
Directories=16
16
22
24
32
36
48
64
72
96
128
192
256
512

Probably not... so this is really messy...

So for now I will probably go with something like this:

// sudo apt install libcairo-dev
// gcc getsize.c $(pkg-config --libs --cflags cairo) $(pkg-config --libs --cflags glib-2.0) -o getsize

#include <cairo.h>
#include <stdio.h>
#include <glib.h>

gchar* determine_icon_destination (gchar *icon_path)
{
    gchar *dest_dir;

    if((g_str_has_suffix (icon_path, ".svg")) || (g_str_has_suffix (icon_path, ".svgz"))) {
        dest_dir = g_build_path("/", g_get_user_data_dir(), "/icons/hicolor/scalable/apps", NULL);
    }

    if((g_str_has_suffix (icon_path, ".png")) || (g_str_has_suffix (icon_path, ".xpm"))) {

        cairo_surface_t *image;

        if(g_str_has_suffix (icon_path, ".xpm")) {
            // TODO: GdkPixbuf has a convenient way to load XPM data. Then you can call
            // gdk_cairo_set_source_pixbuf() to transfer the data to a Cairo surface.
            fprintf(stderr, "XPM size parsing not yet implemented\n");
            return NULL;
        }

        if(g_str_has_suffix (icon_path, ".png")) {
            image = cairo_image_surface_create_from_png(icon_path);
        }

        int w = cairo_image_surface_get_width (image);
        int h = cairo_image_surface_get_height (image);

        // FIXME: The following sizes are taken from the hicolor icon theme. 
        // Probably the right thing to do would be to figure out at runtime which icon sizes are allowable.
        // Or could we put our own index.theme into .local/share/icons/ and have it observed?
        if((w != h) || ((w != 16) && (w != 24) && (w != 32) && (w != 36) && (w != 48) && (w != 64) && (w != 72) && (w != 96) && (w != 128) && (w != 192) && (w != 256) && (w != 512))){
            fprintf(stderr, "%s has nonstandard size w = %i, h = %i; please fix it\n", icon_path, w, h);
            return NULL;
        }

        cairo_surface_destroy (image);

        dest_dir = g_build_path("/", g_get_user_data_dir(), "/icons/hicolor/", g_strdup_printf("%ix%i", w, h), "/apps", NULL);
    }

    return(dest_dir);

}

int main (int argc, char *argv[])
{
    gchar *dest_dir = NULL;
    dest_dir = determine_icon_destination(argv[1]);
    fprintf(stderr, "dest_dir = %s\n", dest_dir);
    return 0;
}
ximion commented 7 years ago

But now the question arises, what do I do with icons that do not fit into the usual suspect sizes like 48x48, 64x64, 128x128, and so on.

That's a bug in the application which should be resolved by the software authors.

Do I really have to resize them first in order for the desktop environment to be able to display them?

Would be ideal, but you could also place them in the size-directory that is the best match. Would be quite ugly, but the DEs will display an icon then (and maybe stretch and distort the image when displaying it, so picking the right size would really be better).

Also, can I be sure to find these sizes on every system?

Yes. That's why we have a standard for it. Having the hicolor theme with the current set of sizes is guaranteed on every DE following the XDG spec (which is, as far as I know, every DE).

So for now I will probably go with something like this: [...]

Looks okay :)

probonopd commented 7 years ago

Thanks @ximion I am going this route now.

azubieta commented 5 years ago

Please move this to tge appimaged repo

rszibele commented 5 years ago

With the current implementation, the menu icons work without issues on Kubuntu 18.10.

I also went ahead and tested other KDE based distributions and it also works without issues on them:

ghost commented 5 years ago

I also went ahead and tested other KDE based distributions and it also works without issues on them:

* KDE Neon user edition 18.04

I am using the most up-to-date version of KDE Neon and it does not work with several appimages (Cryptomator, Jetbrains Toolbox, KeePassXC and many others). https://i.imgur.com/yTMgfq8.jpg

probonopd commented 5 years ago

May well be KDE related since it seems to work in Xfce, tested with https://dl.bintray.com/cryptomator/cryptomator/1.4.9/cryptomator-1.4.9-x86_64.AppImage and https://github.com/keepassxreboot/keepassxc/releases/download/2.4.1/KeePassXC-2.4.1-x86_64.AppImage:

works