Die benutzerdefinierte Rechtsklick-Aktion in Unity Launcher hält den Cursor 20 Sekunden lang beschäftigt

14

Um die Option "Fenster minimieren" durch Klicken mit der rechten Maustaste auf ein Symbol im Unity-Launcher (Ubuntu 14.04) zu erhalten, habe ich die hier aufgeführten Anweisungen zum Ändern einer .desktopDatei befolgt und einen benutzerdefinierten FirefoxLauncher im ~/.local/share/applications/Ordner erstellt. Der relevante Teil der .desktop-Datei ist:

Actions=NewWindow;NewPrivateWindow;Minimize

[Desktop Action NewWindow]
Name=Open a New Window
Exec=firefox -new-window
OnlyShowIn=Unity;

[Desktop Action NewPrivateWindow]
Name=Open a New Private Window
Exec=firefox -private-window
OnlyShowIn=Unity;

[Desktop Action Minimize]
Name=Minimize Windows
Exec=sh /home/myusername/Documents/xdotool_sh/minimize.sh firefox
OnlyShowIn=Unity;

Die Desktop-Aktion "Minimieren" ruft ein einfaches Shell-Skript minimize.shmit folgendem Inhalt auf:

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

Das Skript verwendet xdotool, das aus den offiziellen Repositorys installiert werden kann, um alle firefoxFenster zu finden , über sie zu iterieren und sie zu minimieren.

Das Skript funktioniert und die rechte Menüoption "Windows minimieren" des Launchers funktioniert ebenfalls. Sobald die Fenster jedoch minimiert sind, wechselt der Mauszeiger in den "Beschäftigt" -Modus und bleibt für ca. 20 Sekunden in diesem Zustand (obwohl die Mausaktionen noch aktiv sind ansprechbar).

Weiß jemand, warum das Starten eines Shell-Skripts über eine rechte Menüoption in Unity zu diesem Verhalten führen kann?

EDIT : Anscheinend ist die Wartezeit unvermeidlich, wie in der Antwort von Jacob Vlijm erklärt. Da die Maus weiterhin reagiert , ist das Vermeiden der Transformation des Zeigers im sich drehenden Rad eine teilweise ästhetische Umgehung, wie auf askubuntu erläutert .

EDIT2 : Dem System ein falsches Fenster zu geben, ist eine bessere Lösung, wie von Jacob unten erklärt.

Cosmin Saveanu
quelle
Hallo Cosmin, ich habe eine andere, ziemlich saubere Lösung hinzugefügt, denke ich.
Jacob Vlijm
Vielen Dank, Jacob. Ich dachte über eine solche Lösung nach, wusste aber nicht, wie es gemacht werden könnte. Schön, dass es eine Lösung gibt.
Cosmin Saveanu

Antworten:

18

Hervorragende Frage.

Die Ursache

Normalerweise wartet der Launcher beim Starten von GUI-Anwendungen über Unity Launcher darauf, dass ein Fenster angezeigt wird. Während des Wartens zeigt es das "Spinnrad". Es wird jedoch nicht ewig warten; Nach etwa 20 Sekunden geht der Launcher davon aus, dass das Fenster nicht angezeigt wird, und gibt das Warten auf.

1. Der Hauptbefehl des Startprogramms einer Anwendung

In einer .desktopDatei, die die erste Exec=Zeile (den Hauptbefehl) betrifft , können Sie den Launcher anweisen, in einer Zeile zu warten oder nicht:

StartupNotify=true

um es warten zu lassen, oder

StartupNotify=false

um es nicht warten zu lassen.

2. Quicklist Elemente eines Launchers

Für mögliche Quicklist-Elemente (Rechtsklick) eines Launchers ist der Standardwert jedoch StartupNotify=true. Leider ist dieser Wert fest und kann durch nichts geändert werden.

Das heißt, wenn Sie einen Befehl durch Klicken mit der rechten Maustaste auf ein Starter-Symbol im Unity Launcher starten , erwartet der Launcher ein Fenster und wartet darauf, das sich drehende Rad zu sehen.

Die Quintessenz ist, dass, obwohl es erklärt werden kann, es im Moment keine Lösung für das Problem zu geben scheint, andere als einen dedizierten Launcher für Ihr Skript zu erstellen und die Zeile StartupNotify=falseder Datei hinzuzufügen .

Der Beweis

Sie können das Verhalten selbst testen. Erstellen Sie zwei Trägerraketen:

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

und:

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

Speichern Sie sie als test1.desktopund test2.desktopziehen Sie beide Starter auf den Unity-Starter. Klicken Sie darauf und sehen Sie den Unterschied im Verhalten.


Bearbeiten; Wenn es dich wirklich stört, füttere Unity ein falsches Fenster

Wenn Sie viele Skripte in Schnelllisten haben und / oder es Sie wirklich stört, gibt es eine andere kosmetische Lösung; Wir können fälschen , unsichtbar (vollständig transparent), um ein Fenster anzuzeigen, das in Ihr Skript aufgenommen werden soll. Ihr Skript wäre dann (zB)

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

Hier fake_windowruft der Befehl unser (Fake-) Fenster auf, wodurch Unity das Rad zum Stillstand bringt.

Wie stellt man das ein

  1. Erstellen Sie das Verzeichnis, falls es noch nicht existiert ~/bin
  2. Kopieren Sie das folgende Skript in eine leere Datei, speichern Sie es als fake_window(keine Erweiterung) in ~/bin und machen Sie es ausführbar

    #!/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. Fügen Sie ganz am Ende Ihres Skripts den folgenden Befehl hinzu:

    fake_window
  4. Abmelden und wieder anmelden (oder ausführensource ~/.profile)

Das Rad dreht sich jetzt nur so lange, wie das Skript ausgeführt wird.

Erläuterung

Das Skript hat ein minimalistisches Fenster erstellen. Das Fenster ist jedoch vollständig transparent und hat eine Größe von 0x0 Pixel und ist somit unsichtbar. Es wird sich sofort selbst zerstören, sobald es existiert.

Wenn Sie das Fenster am Ende Ihres Skripts aufrufen, werden Sie Unitys Wunsch nach einem Fenster erfüllen und das Rad anhalten, um sich zu drehen.

Jacob Vlijm
quelle
Vielen Dank für die ausführliche Erklärung und Bearbeitung der Frage. Gibt Anregungen zu möglichen Problemumgehungen.
Cosmin Saveanu
Tolle Idee - ein falsches Fenster geben. Ich mag es
Sergiy Kolodyazhnyy
@ Serg Trick und Betrug, aber es funktioniert :)
Jacob Vlijm
4

Ich wollte nur eine alternative fake_window-Implementierung hinzufügen, die etwas einfacher ist und auf einem Ubuntu 16.04-System keine Python-Warnungen auslöst.

#!/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()
Digikata
quelle
Nice! never noticed this addition until now :)
Jacob Vlijm