7

With Ubuntu 16.04, if you create a launcher (desktop file in ~/.local/share/applications) with a custom icon for a terminal application (so with Terminal=true) then when you start it, it will spawn a new standard terminal icon, and your custom icon will pulse and disappear within a few seconds.

In 14.04, it just worked as expected. (it would not start a new standard terminal icon).

Any idea what to do to change this behaviour? I have a few terminal apps that I want to launch from unity and the new behaviour is problematic (I lose trace of which is which since they all end up with the standard terminal icon)...

2
  • 1
    The behaviour was and is: an application can only be represented by one icon in the launcher at a time. I can tell you how to make it work for a terminal app (one at a time), but it is bad practice. Better make them quicklist entries for the existing terminal launcher. Jun 20, 2016 at 19:55
  • 1
    The behaviour has changed in 16.04 compared to 14.04! I know for sure, since I use the exact same desktop files, just installed 16.04 a few days ago. Yes, please, how to make it work for a terminal? Quicklist entry is no good for me, as I still want to launch from the dash. Currently my apps running in a terminal show fine in the dash, with the custom icon I set. However, when I launch them, first the custom icon appear in the Unity launch bar, then a second icon with standard terminal appear and the first one pulses for a few seconds...
    – Se6
    Jun 21, 2016 at 8:35

4 Answers 4

7

Why it doesn't work like you do

As mentioned in the comment, an application in principle can only be represented by one icon in the launcher at a time. This has always been the case.

What you are referring to is probably that Unity has become "smarter" in determining which of the .desktop files is the best representative for the application's window. Therefore, your script, running a terminal window, will be represented by the gnome-terminal -icon:

enter image description here

Therefore, what worked in the past in your setup, simply creating a launcher, starting your script, doesn't fool Unity anymore, and it picks the existing gnome-terminal launcher to represent your window.

The bad solution

...is to overrule Unity's choice by adding a line to your launcher (for 16.04):

StartupWMClass=gnome-terminal-server

enter image description here

...but then all terminal windows, no matter if they run your script or not, are grouped under this icon.

Furthermore, in general, having multiple .desktop files, calling the same application in their main command is bad, unclean practice.


EDIT

How to have (a) separate icon(s) for a running script(s)

It takes a bit of trickery and deceit, but it is possible to have a separate icon for multiple scripts, running in different terminal windows.

How it works in practice

  • Say you have a script, somscript.sh, which you want to run in a terminal window, showing its dedicated icon in the Unity Launcher while it runs.
  • Run the command:

    showicon somescript.sh someicon.png
    

    and the script will run inside a newly opened gnome-terminal window, showing the icon: someicon.png

  • If the window is closed, the icon is removed from the launcher again.

An example

  • I want a script, /home/jacob/Bureaublad/script.sh, run, showing in the Unity launcher with icon: /home/jacob/Thema/icon/ubu.png Running the command:

    showicon '/home/jacob/Bureaublad/script.sh' '/home/jacob/Thema/icon/ubu.png'
    

    will do that:

    enter image description here

    Now let's add another one:

    showicon '/home/jacob/Bureaublad/script2.sh' '/home/jacob/Thema/icon/banaan.png'
    

    The result:

    enter image description here

    Once the windows are closed, the icon(s) are removed again.

How to setup

  1. The script needs wmctrl

    sudo apt-get install wmctrl
    
  2. Create, if it doesn't exist yet, the directory ~/bin

  3. Copy the script below into an empty file, save it as showicon (no extension) in ~/bin, and make it executable
  4. Log out and back in, your setup should work. Test it with the command

    showicon </path/to/script.sh> </path/to/icon.png>
    

    to have script.sh run in a terminal, showing icon.png in the Unity launcher.

The script

#!/usr/bin/env python3
import subprocess
import os
import sys
import time

terminal = "gnome-terminal"
key = "com.canonical.Unity.Launcher"
script = sys.argv[1]
icon = sys.argv[2]

curr = os.path.dirname(os.path.realpath(__file__))
scriptname = script.split("/")[-1]

def get(command):
    try:
        return subprocess.check_output(command).decode("utf-8")
    except subprocess.CalledProcessError:
        pass

# --- edit Unity launcher section

def current_launcher():
    return eval(get(["gsettings", "get", key, "favorites"]))

def set_launcher(desktopfile, arg):
    curr_launcher = current_launcher()
    last = [i for i, x in enumerate(curr_launcher) if x.startswith("application://")][-1]
    new_icon = "application://"+desktopfile
    if arg == "a":
        if not new_icon in curr_launcher:
            curr_launcher.insert(0, new_icon)
            subprocess.Popen(["gsettings", "set", key,"favorites",str(curr_launcher)])
    elif arg == "r":
        curr_launcher.remove(new_icon)
        subprocess.Popen(["gsettings", "set", key,"favorites",str(curr_launcher)])

# --- end section

def create_launcher(w, scriptname, icon):
    launcher = ["[Desktop Entry]", "Type=Application",
            "Exec=wmctrl -ia "+w, "Name="+scriptname, "Icon="+icon,
            "StartupNotify=False"]
    with open(l_name, "wt") as newlauncher:
        for l in launcher:
            newlauncher.write(l+"\n")

def getname():
    # create unique launcher name
    n = 1
    while True:
        nm = os.path.join(curr, "scriptlauncher_"+str(n)+".desktop")
        if os.path.exists(nm):
            n += 1
        else:
            break
    return nm    

wlist1 = [l.split()[0] for l in get(["wmctrl", "-l"]).splitlines()]
subprocess.Popen(["gnome-terminal", "-e", script])

while True:
    time.sleep(1)
    wdata = get(["wmctrl", "-l"]).splitlines()
    if wdata:
        try:
            wlist2 = [l.split()[0] for l in wdata]
            w = [w for w in wlist2 if not w in wlist1][0]
        except IndexError:
            pass
        else:
            # check if the new window belongs to the terminal
            if terminal in get(["xprop", "-id", w]):
                # create launcher
                l_name = getname()
                create_launcher(w, scriptname, icon)
                set_launcher(l_name, "a")
                break
    wlist1 = wlist2

while True:
    time.sleep(2)
    wdata = get(["wmctrl", "-l"])
    if wdata:
        if not w in wdata:
            os.remove(l_name)
            set_launcher(l_name, "r")
            break 

Note

  • What the icon does:

    • It represents the gnome-terminal window, running your script
    • When clicking on it, it raises the window, as usual. The command to do so is automatically added to the temporary launcher:

      wmctrl -ia <window_id>
      
  • What it does not:

    • The only downside of this solution is that the icon does not show the usual arrow on the left for running apps, since the representation is indirect.

Explanation

Without going too much into detail:

  • The script is a wrapper. If you launch your script via showicon, an instance of showicon runs your script in a gnome-terminal window, similar to Terminal=true.
  • Subsequently, showicon waits for the new gnome-terminal window to appear and reads its window id.
  • A temporary launcher is then created, using the window id to create the command to raise the window in its Exec= line. The icon you set as argument in the command to run showicon is automatically set as icon of this temporary launcher (defined in the line Icon=).

    an example of such an automatically created (temporary) launcher:

    [Desktop Entry]
    Type=Application
    Exec=wmctrl -ia 0x04400b7f
    Name=script2.sh
    Icon=/home/jacob/Thema/icon/ubu.png
    StartupNotify=False
    
  • Using the very same procedure as in this answer, the temporary launcher is added to the Unity Launcher, in the top position, to represent your running script.

  • In the meantime, showicon checks for the window to exist. If not (anymore), the temporary launcher is removed from the Unity launcher and removed from existence at all, and the showicon instance is terminated.
7
  • In 16.04, there seems to no way I can get 2 different terminal app having 2 different icons then.
    – Se6
    Jun 21, 2016 at 13:01
  • @Se6 not in sense that you asked for. There are other options though to show the existence of processes like running scripts, in either the launcher or the panel. Interested? Jun 25, 2016 at 11:50
  • sure, would be interested.
    – Se6
    Jun 25, 2016 at 15:26
  • Thanks a lot Jacob for this. Will implement it. Sad we have to do that much trickery just to get the icon of our choice to represent a terminal app, but it is what it is.
    – Se6
    Jun 26, 2016 at 19:31
  • Hi @Se6 I am afraid this is the maximum we can achieve within the limits of Unity. Once set up, it should run rather simple and straightforward though. Jun 26, 2016 at 19:33
2

I found a simple solution that works in Ubuntu 20.04.

This works for any script or terminal application which you want to run with its own icon and name integrated into the dock, rather than in just another terminal window.

You do not need to install anything, it is all done within the launcher .desktop file. Here is my example for launching the terminal text editor micro.

[Desktop Entry]

Name=Micro
GenericName=Text Editor
Comment=Edit text files in a terminal

Icon=micro
Type=Application
Categories=Utility;TextEditor;Development;
Keywords=text;editor;syntax;terminal;

Exec=gnome-terminal -e "micro %F" -t "Micro" --hide-menubar --name=Micro --class=micro
StartupNotify=true
Terminal=false
MimeType=text/plain;text/x-chdr;text/x-csrc;text/x-c++hdr;text/x-c++src;text/x-java;text/x-dsrc;text/x-pascal;text/x-perl;text/x-python;application/x-php;application/x-httpd-php3;application/x-httpd-php4;application/x-httpd-php5;application/xml;text/html;text/css;text/x-sql;text/x-diff;

The main options to take note are:

  • Exec line launches gnome-terminal with the command (-e "YOUR COMMAND") PLUS the arguments -t "Micro" --hide-menubar --name=Micro --class=micro. These will set up the terminal window with the name of your application (in this case Micro) as well as its class, so that it does not merge into just another terminal class window.
  • StartupNotify=true This ensures that if you have the launcher as a favourite, it gets stacked when you launch it instead of adding additional icon instances.
  • Terminal=false Use this to avoid an additional terminal window popping up, UNLESS you actually want to see that window.
1
  • That is brilliant thanks! I just had to change the -e option which is now deprecated and put the command at the end after a --
    – Se6
    Sep 3, 2021 at 7:11
1

Another not answer but solution.

I use quicklists to create launchers for my most commonly used terminal sessions, i then make profiles for each one in gnome-terminal to do things like change their colours, this makes it really easy to know which server you are using.

You can do this by editing your gnome-terminal.desktop file in ~/.local/share/applications/gnome-terminal.desktop.

mine looks like this

[Desktop Entry]
Name=Terminal
Comment=Use the command line
Keywords=shell;prompt;command;commandline;
TryExec=gnome-terminal
Exec=gnome-terminal
Icon=utilities-terminal
Type=Application
X-GNOME-DocPath=gnome-terminal/index.html
X-GNOME-Bugzilla-Bugzilla=GNOME
X-GNOME-Bugzilla-Product=gnome-terminal
X-GNOME-Bugzilla-Component=BugBuddyBugs
X-GNOME-Bugzilla-Version=3.16.2
Categories=GNOME;GTK;System;TerminalEmulator;
StartupNotify=true
X-GNOME-SingleWindow=false
OnlyShowIn=GNOME;Unity;
Actions=New;Item1;Item2
X-Ubuntu-Gettext-Domain=gnome-terminal

[Desktop Action New]
Name=New Terminal
Exec=gnome-terminal
OnlyShowIn=Unity

[Desktop Action Item1]
Name=SSH Shell type 1
Exec=gnome-terminal -e 'ssh item1' --profile 'Item1'
OnlyShowIn=Unity


[Desktop Action Item2]
Name=SSH Shell type 2
Exec=gnome-terminal -e 'ssh item2' --profile 'Item2'
OnlyShowIn=Unity

I also wrote a script a while ago to automate adding entries to your quicklist from the hostsfile so any ssh command gets a quicklist entry. I wrote it when quicklists didn't get updated automatically and gave up because that made it clunky , now they are instant it could run via a cron job.

http://blog.amias.net/articles/114

2
  • Thanks, interesting indeed. What I was looking for though is a way to have 2 different terminal apps represented by 2 different and custom icons. I can have that in Dash, but then when it runs, Unity replaces my custom one by a standard Terminal one.
    – Se6
    Jun 21, 2016 at 13:00
  • i don't think its still supported but there is an ANSI escape sequence for that which is documented here unix.stackexchange.com/questions/265760/…
    – Amias
    Jun 21, 2016 at 15:50
0

A one time fix would be to write a small executable program that runs your script, and assign an unique launcher icon to the executable.

1
  • an executable without a window would not show in the Unity launcher, Since the terminal window would be the only appearing window, it would show under gnome-terminal. Jun 28, 2016 at 5:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .