Custom right-click action in Unity Launcher keeps cursor busy for 20 seconds

Excellent question.

The cause

Normally, when starting GUI applications from the Unity Launcher, the launcher waits for a window to appear. While waiting, it shows the "spinning wheel". It won't wait forever however; after about 20 seconds, the launcher assumes the window won't appear and gives up waiting.

1. The main command of an application's launcher

In a .desktop file, concerning the first Exec= line (the main command), you can tell the launcher to wait or not, in a line:

StartupNotify=true

to make it wait, or

StartupNotify=false

to make it not wait.

2. Quicklist items of a launcher

For possible quicklist (right-click) items of a launcher however, the default value is StartupNotify=true. Unfortunately, this value is fixed and cannot be changed by anything.

That means that if you start any command from right-clicking a launcher icon in the Unity Launcher, the launcher is expecting a window and waits for it, showing the spinning wheel.

The bottom line is that, although it can be explained, there seems to be no solution to the issue at the moment, other then creating a dedicated launcher for your script and add the line StartupNotify=false to the file.

The proof

You can test the behaviour yourself. Create two launchers:

[Desktop Entry]
Name=Test
Exec=sh /home/myusername/Documents/xdotool_sh/minimize.sh firefox
Type=Application
StartupNotify=true

and:

[Desktop Entry]
Name=Test
Exec=sh /home/myusername/Documents/xdotool_sh/minimize.sh firefox
Type=Application
StartupNotify=false

Save them as test1.desktop and test2.desktop, drag both launchers on to the Unity launcher. Click them and see the difference in behaviour.


Edit; if it really bothers you, feed Unity a fake window

If you have many scripts in quicklists, and/or it really bothers you, there is another cosmetic solution; we can fake, invisible (fully transparent) to show a window, to be included in your script. your script would then be (e.g.)

#/bin/bash
name=$1
for i in $(xdotool search --class "$name"); do
    xdotool windowminimize $i
done
fake_window

where the command fake_window will call our (fake-) window, making Unity end the spinning wheel.

How to set up

  1. Create, if it does not exist yet, the directory ~/bin
  2. Copy the script below into an empty file, save it as fake_window (no extension) in ~/bin and make it executable

    #!/usr/bin/env python3
    from gi.repository import Gtk
    from threading import Thread
    import time
    import subprocess
    
    """
    This is a self-destroying window, to "feed" Unity a fake-window, preventing
    the launcher to show a spinning wheel, waiting for a window to appear.
    Include the command to run this script at the end of the (your) script.
    """
    
    class FakeWin(Gtk.Window):
    
        def __init__(self):
            Gtk.Window.__init__(self, title="1526closeme")
            Thread(target = self.close).start()
    
        def close(self):
            t = 0
            while t < 150:
                time.sleep(0.2)
                try:
                    pid = subprocess.check_output(["pgrep", "-f", "fake_window"])\
                          .decode("utf-8").strip()
                    subprocess.Popen(["kill", pid])
                    break
                except subprocess.CalledProcessError:
                    pass
                t += 1
    
    def fakewindow():
        window = FakeWin()
        # make our window transparent
        window.set_opacity(0)
        window.set_default_size(0,0)
        window.show_all()
        Gtk.main()
    
    fakewindow()
    
  3. Add to the very end of your script the command:

    fake_window
    
  4. Log out and back in (or run source ~/.profile)

That's it, the wheel will now only spin for as long as the script runs.

Explanation

The script does create a minimalistic window. The window however is fully transparent and has a size of 0x0 pixels and is thus invisible. It will destroy itself instantly once it exists.

Calling the window at the end of your script, you will satisfy Unity's wish for a window, stopping the wheel to spin.


Just wanted to add an alternate fake_window implementation that is a little bit simpler and doesn't trigger python warnings on an Ubuntu 16.04 system.

#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '3.0')

from gi.repository import Gtk
from gi.repository import GLib

"""
This is a self-destroying window, to "feed" Unity a fake-window, preventing
the launcher to show a spinning wheel, waiting for a window to appear.
Include the command to run this script at the end of the (your) script.
"""

def timer_cb():
    Gtk.main_quit()
    return False

def show_cb(widget, data=None):
    GLib.timeout_add(500, timer_cb)

def fakewindow():
    window = Gtk.Window()
    # make our window transparent
    window.set_opacity(0)
    window.set_default_size(0,0)

    window.connect("show", show_cb)

    window.show_all()

    Gtk.main()

fakewindow()