App icon doesn't appear in Linux

I can’t get my app icon to show up in the Linux cpp target. I’ve tried specifying an svg and specifying various sizes of png, no difference.

Possibly relevant: a friend told me “SDL 2 is pickier about what it’ll accept for an icon than SDL 1, and setting an 512x512 icon no longer works. 256x256 works for me.” - that’s referring to SDL2 vs. SDL1 rather than anything specific to OpenFL though.

Lime: 2.0.0
OpenFL: latest git version

Do you mean on the executable, in the window, in alt+tab?

I have the same problem.
There is a generic question mark icon in Ubuntu Launcher when the app runs.
Also I couldn’t find anything similar to an icon in the export/linux64/cpp folder.

It might be related to building on Linux and missing some libs for .svg processing.
Because Neko builds on linux don’t have icons as well.

Perhaps there’s some way to set a desktop entry:

If someone can figure out a good format we can generate it automatically when building

It’s not so much a build problem as it is a deploy/install problem. According to these two articles:

http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html#install_icons

Binaries don’t include icons, instead an application file (.desktop suffix) defines the executable and icon. Unfortunately, these paths must be absolute (ouch), and the desktop file typically resides in /usr/share/, which means it must be installed by root. This is typically all setup by the apt-get package installation process.

For me, I don’t want an “installer” nor do I want to require root permissions. I just want a user to download and run my app, and get a nice icon.

Luckily (on Ubuntu at least) there is a user-owned mirror directory in ~/.local/share/... where you can put your .desktop file and .svg icon. So you can write them there as part of your start-up, but then the tricks will be 1) writing it there (I presume) before your app starts (installer oe start-up script? separate launch app?), and 2) you’ll need to write into those files the absolute path of your executable and icon, also repairing these paths if the user moves the executable.

Anyway, fun fun. I got it to work by installing this by hand, and I’m considering writing the files as part of a splash screen:

>cat ~/.local/share/applications/hxScout.desktop 
[Desktop Entry]
Encoding=UTF-8
Version=1.0
Type=Application
Terminal=false
Exec=/home/jward/Downloads/hxScout-0.4.0-linux/hxScout
Name=hxScout
Icon=/home/jward/.local/share/icons/hxScout.svg

Might have to run the gtk icon cache cleaner (still no root necessary):

> gtk-update-icon-cache /usr/share/icons/hicolor

Then, tada:

Also works beautifully in the app switcher (alt-tab).

1 Like

Does that work on first run?

Dunno, I set it up manually and it worked. So now I have to try “first run” ideas (script, separate splash app writes it, app could write files then restart itself, etc.)

I would be happy to consider adding a standard icon file (can it be PNG?) to Linux builds, then perhaps the standard ApplicationMain could (in a try/catch manner) look for the .desktop file and generate if it is not present

Yes, it can be PNG.

So it’s very odd what I had to do. In ApplicationMain.hx, if the .desktop file doesn’t exist, I write it and then close this process and re-launch, but I have to wait a couple seconds (see sleep 2) or the icon doesn’t show up. I even did file flush and close… hmm… this delay isn’t ideal, I wonder why it doesn’t pick it up without the sleep.

(This still has a bunch of hardcoded stuff for testing, e.g. executable location, and isn’t writing the icon file yet. This snippet is just for discussion.)

#if linux
var desktop = "[Desktop Entry]\nEncoding=UTF-8\nVersion=1.0\nType=Application\nTerminal=false\nExec=/home/jward/dev/hxScout/proj/export/legacy_release_notelemetry/linux64/cpp/bin/hxScout\nName=hxScout\nIcon=/home/jward/.local/share/icons/hxScout.svg\n";
var home = Sys.environment().get("HOME");
var desktop_file = home+"/.local/share/applications/hxScout.desktop";
if (!sys.FileSystem.exists(desktop_file)) {
  var out = sys.io.File.write(desktop_file, false);
  out.writeString(desktop);
  out.flush();
  out.close();

  trace("Rerun: "+Sys.getCwd()+Sys.executablePath());
  Sys.command("(sleep 2; "+Sys.getCwd()+Sys.executablePath()+") &");
  trace("Exiting...");
  Sys.exit(0);
  return;
}
	#end

What about the update-icon-cache?

I had tried that, it didn’t make a difference.

Hmm, now that I think about it – I’m expecting linux users to untar my application before using it. I could instead deliver a self-extracting installer script. At that point, I could detect sudo and install either in /usr locations, or for non-root install under the home directory. But I personally like archives and dislike installers, because the latter obfuscates exactly what’s happening.

For me, perhaps I’ll make my splash screen do the icon setup for the main app – then the two-second delay is acceptable. But unfortunately that’s not for everybody.

Does this help?

http://linux.die.net/man/1/xdg-desktop-menu

That utility appears to install the .desktop file (and as a bonus, inserts hxScout into the start menu.) But fascinatingly, there still needs to be a time gap between .desktop file write and app launch.

BTW, is there a template variable for one of the project xml <icon> paths? Maybe the largest or an SVG? I see ::WIN_ICON:: but it’s null in the linux build.

Perhaps we should generate the icon in the tools to a standard file name, such as icon.png or icon-512.png, then you could rely on it being in a standard place.

What happens if you run the utility to install on first-run, does it appear on second-run?

Yes, a standard name would allow us to populate Icon=<CWD>+icon.png

What happens if you run the utility to install on first-run, does it appear on second-run?

Right, without the delay, the icon shows up fine on the second run. But I do have code where it displays:

>./hxScout
Installing app icon...
(2 second pause, then launch as normal)

This feels alright. Could be optional…

Does it close and open itself, or do you have a shim as a second executable?

Same executable. This is what I’m starting to like, but it 1) hard codes Icon path, and 2) doesn’t work when called from lime or openfl command wrappers, because Sys.executablePath returns /usr/bin/lime

#if linux
var exec_path = Sys.executablePath();
if (exec_path.substr(0,1)!="/") exec_path = Sys.getCwd()+Sys.executablePath();
var desktop = "[Desktop Entry]\nEncoding=UTF-8\nVersion=1.0\nType=Application\nTerminal=false\nExec="+exec_path+"\nName="+"::APP_TITLE::"+"\nIcon=/home/jward/.local/share/icons/hxScout.svg\n";
var home = Sys.environment().get("HOME");
var desktop_path = home+"/.local/share/applications";
var desktop_file = desktop_path + "/hxScout.desktop";
if (sys.FileSystem.exists(exec_path) && sys.FileSystem.exists(desktop_path) && !sys.FileSystem.exists(desktop_file)) {
  try {
    var out = sys.io.File.write(desktop_file, false);
    out.writeString(desktop);
    out.flush();
    out.close();

    Sys.stdout().writeString("Setup GTK icon file, "+desktop_file+"\n");
    Sys.sleep(2);
    Sys.command(exec_path);
    Sys.exit(0);
  } catch (e:Dynamic) { }
}
	#end

ETA: Oh, I should probably pass Sys.args() along – that might fix it for lime and openfl as well…

Someone on Super User pointed me to: https://developer.gnome.org/gtk3/stable/GtkWindow.html#gtk-window-set-icon

Is SDL doing this? If not, this may be an easier runtime solution than a .desktop file.

You could try it:

Hmm, I’ve never used any classes out of Lime and I can’t get it the import to work (nevermind the Image type – I assume Bitmap is related…)