web-dev-qa-db-fra.com

Un clic droit personnalisé dans Unity Launcher maintient le curseur occupé pendant 20 secondes

Pour avoir une option "réduire la fenêtre" par un clic droit sur une icône du lanceur Unity (Ubuntu 14.04), j'ai suivi les instructions détaillées ici sur la modification d'un fichier .desktop et créé un lanceur personnalisé Firefoxdans le dossier ~/.local/share/applications/ . La partie pertinente du fichier .desktop est:

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;

L'action de bureau "Réduire" appelle un script Shell simple, minimize.sh, dont le contenu est le suivant:

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

Le script utilise xdotoolname__, qui peut être installé à partir des référentiels officiels, pour rechercher toutes les fenêtres firefoxname__, les parcourir et les minimiser.

Le script fonctionne et l'option de menu de droite du lanceur "Réduire Windows" fonctionne également, mais dès que les fenêtres sont réduites au minimum, le pointeur de la souris passe en mode "occupé" et reste ainsi pendant environ 20 secondes (bien que les actions de la souris restent sensible).

Quelqu'un sait-il pourquoi le démarrage d'un script Shell à partir d'une option de menu de droite dans Unity pourrait entraîner ce comportement?

EDIT: Apparemment, la période d'attente est inévitable, comme expliqué dans la réponse de Jacob Vlijm. Puisque la souris reste sensible, éviter la transformation du pointeur dans le rouet est une solution de contournement esthétique partielle, comme expliqué sur askubunt .

EDIT2 : donner au système une fausse fenêtre est une meilleure solution, comme l'explique Jacob ci-dessous.

14
Cosmin Saveanu

Excellente question.

La cause

Normalement, lors du démarrage des applications GUI à partir du lanceur Unity, le lanceur attend qu'une fenêtre apparaisse. En attendant, il montre le "rouet". Il n'attendra pas pour toujours cependant; après environ 20 secondes, le lanceur suppose que la fenêtre n'apparaîtra pas et abandonne l'attente.

1. La commande principale du lanceur d'application

Dans un fichier .desktop, concernant la première ligne Exec= (la commande principale), vous pouvez dire au lanceur d'attendre ou non, dans une ligne:

StartupNotify=true

pour le faire attendre, ou

StartupNotify=false

pour le faire pas attendre.

2. Éléments de liste rapide d'un lanceur

Pour les éléments de liste rapide possibles (clic droit) d'un lanceur, la valeur par défaut est StartupNotify=true. Malheureusement, cette valeur est fixe et ne peut être modifiée par rien.

Cela signifie que si vous lancez toute commande en cliquant avec le bouton droit de la souris sur l’icône du lanceur dans le lanceur Unity, le lanceur attend une fenêtre et attend, en indiquant le rouet.

L’essentiel est que, bien que cela puisse être expliqué, il ne semble pas y avoir de solution au problème pour le moment, à part créer un programme de lancement dédié à votre script et ajouter la ligne StartupNotify=false au fichier.

La preuve

Vous pouvez tester le comportement vous-même. Créez deux lanceurs:

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

et:

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

Enregistrez-les sous les noms test1.desktop et test2.desktop, faites glisser les deux lanceurs sur le lanceur Unity. Cliquez dessus et voyez la différence de comportement.


Modifier; si ça vraiment vous dérange, donnez à Unity une fausse fenêtre

Si vous avez de nombreux scripts dans des listes rapides et/ou que cela vous dérange vraiment, il existe une autre solution esthétique. nous pouvons simuler , invisible (totalement transparent) pour afficher une fenêtre, à inclure dans votre script. votre script serait alors (par exemple)

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

où la commande fake_window appellera notre (fausse) fenêtre, faisant en sorte que Unity termine la roue en rotation.

Comment mettre en place

  1. Créez, s'il n'existe pas encore, le répertoire ~/bin
  2. Copiez le script ci-dessous dans un fichier vide, enregistrez-le sous fake_window (sans extension) dans ~/bin et rendez-le exécutable

    #!/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. Ajoutez à la toute fin de votre script la commande:

    fake_window
    
  4. Déconnectez-vous et reconnectez-vous (ou exécutez source ~/.profile)

Ça y est, la roue ne tournera que tant que le script fonctionnera.

Explication

Le script crée une fenêtre minimaliste. La fenêtre est cependant totalement transparente et a une taille de 0x0 pixels et est donc invisible. Il va se détruire instantanément une fois qu'il existe.

En appelant la fenêtre à la fin de votre script, vous satisferez le souhait de Unity de disposer d’une fenêtre, en arrêtant la roue de tourner.

18
Jacob Vlijm

Je voulais juste ajouter une autre implémentation de fake_window qui est un peu plus simple et ne déclenche pas python avertissements sur un système Ubuntu 16.04.

#!/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()
4
Digikata