web-dev-qa-db-fra.com

Lancer l'application seulement si elle n'est pas déjà ouverte

J'aimerais imiter l'utilisation d'Alfred sur Mac OS X. Si vous essayez d'ouvrir une application après l'avoir recherchée, une nouvelle fenêtre ne s'ouvrira que si le programme ne fonctionne pas déjà, sinon, l'accent sera mis sur le instance en cours d'exécution de cette application. Est-il possible de changer le comportement par défaut du lanceur pour vérifier cela avant d'ouvrir une nouvelle fenêtre?

15
Dan Jenson

Mise à jour du 7 avril: Une version différente a été ajoutée et trouvée par Albert, voir mise à jour et bonus ci-dessous !!!

Concernant la fonctionnalité de tiret : Vous avez demandé ". Est-il quand même possible de modifier le comportement par défaut du lanceur afin de vérifier cela avant de l'ouvrir une nouvelle fenêtre ". La réponse de base est non, en tant qu’utilisateur régulier, vous n’avez aucun moyen d’ajouter ce comportement au tiret. Cependant, s'il y avait un développeur d'unité qui serait prêt à mettre cela en œuvre, vous pouvez le contacter ou en développer un vous-même si vous êtes résolu et disposé à apprendre. Mes compétences en matière de codage étant très modestes, j’utilise les scripts Shell et l’interface graphique disponible pour les scripts en guise de solution de contournement.

Informations connexes

Message original:

J'ai écrit un script qui utilise le dialogue zenity et wmctrl pour réaliser ce que vous avez demandé. Notez qu'il s'agit d'un script graphique, ce qui signifie qu'il ne fonctionnera qu'avec Windows, dans l'interface graphique, et ne fonctionnera pas si vous essayez de lancer quelque chose dans tty. En outre, d'après ce que je comprends, Alfred fait exactement la même chose. Vous pouvez créer un raccourci sur le bureau ou un raccourci de lancement, comme décrit ici et ici .

Le scénario:

#!/bin/bash
# Author: Serg Kolo
# Description: A launcher script that checks whether
#       or not a window of a particular program already exists
#       If a window of such program is open, bring it to focus
#       Otherwise - launch a new window
#       Written for https://askubuntu.com/q/440142/295286
# Date: April 6 , 2015
#


MYPROG=$( zenity --entry --title='MY LAUNCHER' --text='Type the name of application to run' )
sleep 0.5
wmctrl -lx | awk '{print $3}' | grep -i "$MYPROG"

if [ $? -eq 0 ]; then
    sleep 1         
    wmctrl -xa $MYPROG
   #as an alternative try the line bellow
   #wmctrl -a $MYPROG
    exit 1
else 
    $MYPROG &
    exit 0
fi

Notes annexes: dans la version précédente, le script utilisait echo $ ?, pour vérifier si les expressions précédentes se sont terminées avec succès. Selon la suggestion de muru (de la modification), j'ai changé le code pour une version un peu plus compacte, je vous suggère donc de jeter un coup d'œil à la version précédente et à la version actuelle.

De plus, wmctrl -a $MYPROG ne fonctionnait pas avec Google Chrome ou Chrome Chrome Browser; pour une raison quelconque, certains programmes ont la propriété WM_CLASS de la fenêtre mise en majuscule, tandis que le programme répertorié par dpkg --get-selections est en minuscule (il suffit de lire man wmctrl et d'exécuter wmctrl -lx, vous le saurez). L'ajout de -ax devrait résoudre ce problème. Le script ouvre la fenêtre de chrome déjà ouverte comme il se doit

Une autre chose - wmctlr est un peu bizarre dans la mesure où il a parfois besoin d’un délai (j’en ai fait l’expérience dans un autre script), donc j’ai dû ajouter sleep 1 line. Auparavant, firefox fonctionnait un peu, mais fonctionne maintenant à la perfection.

Le script en action

Dans l'animation ci-dessous, vous pouvez voir que lors de la première exécution du script, une instance de Firefox est ouverte et que le script active la fenêtre correspondante. lors du deuxième test, j'ouvre une nouvelle instance de google-chrome, qui n'a pas été ouverte auparavant. (Note: si vous êtes curieux à propos du bureau, soit dit en passant, openbox avec cairo dock)

Par suggestion dans les commentaires, animation intégrée supprimée, lien posté uniquement. Signaler s'il est cassé s'il vous plait! http://i.stack.imgur.com/puuPZ.gif

Mise à jour du 7 avril

J'ai quelque peu amélioré le script pour rendre tous les programmes répertoriés dans la liste déroulante de zenity. Maintenant, l'utilisateur n'a pas à mémoriser chaque programme, mais peut simplement faire défiler une liste d'entre eux à l'aide des touches fléchées ou simplement ouvrir le menu déroulant. En outre, cette version améliorée lève les fenêtres non pas par leur nom, mais par leur id de fenêtre, ce qui donne de bien meilleures performances. Notez que la façon dont je parcours les fichiers .desktop est assez redondante, en utilisant la commande cut deux fois, mais comme mon script-fu n’est pas aussi bon, c’est tout ce que je peux faire. Les suggestions d'amélioration sont les bienvenues!

#!/bin/bash
# Author: Serg Kolo
# Description: Second version of a launcher script that checks whether
#       or not a window of a particular program already exists
#       If a window of such program is open, bring it to focus
#       Otherwise - launch a new window
#       Written for https://askubuntu.com/q/440142/295286
# Date: April 7 , 2015
#

set -x

MYPROG=$(zenity --entry --text 'Select program from list' --entry-text $(ls /usr/share/applications/*.desktop | cut -d'/' -f5 | cut -d'.' -f1 | xargs echo))
sleep 0.5
# Do we have a window of such program ?
wmctrl -lx| awk '{print $3}'  | grep -i $MYPROG

if [ $? -eq 0 ]; then
    sleep 0.5 # if yes, find that window id, and raise it
    WINID=$(wmctrl -lx | grep -i $MYPROG | awk 'NR==1{print $1}')
    wmctrl -ia $WINID &
 #  exit 0  
else
    echo $MYPROG | grep -i libreoffice
    if [ $? -eq 0  ]
    then
        MYPROG=$(echo $MYPROG | sed 's/-/ --/g')
    fi
    $MYPROG &

#  exit 0 
fi

enter image description here

Bonus:

J'ai effectivement trouvé Albert , qui est la version Linux d'Alfred, mais je ne l'ai pas essayé moi-même. Cela vaut la peine de vérifier si. Cependant, comme Jacob l'a déjà noté, il est toujours buggé.

Il existe une application appelée Gnome-Do, qui ressemble graphiquement à Alfred, mais qui n’a pas les mêmes fonctionnalités que ce script.

enter image description here

Faites-moi savoir si vous aimez ce script, s'il y a quelque chose à corriger, et n'oubliez pas de changer la réponse si vous le jugez utile

6

1. Dash le second

Ci-dessous, un script qui peut être utilisé comme alternative à Dash, lorsqu'il s'agit d'exécuter des applications comme décrit dans votre question.

Il existe une fenêtre avec les mêmes fonctionnalités que Dash; si vous tapez un ou plusieurs caractères de l’application, celle-ci apparaîtra dans la liste. presse Enter pour démarrer ou élever l’application, selon qu’elle est déjà en cours d’exécution ou non.

Vous pouvez l'appeler à partir d'une combinaison de touches de raccourci ou définir une icône dans le programme de lancement pour l'utiliser de la même manière que Dash (voir ci-dessous) ou les deux.

enter image description here

Le scénario

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

user = getpass.getuser()
get = lambda x: subprocess.check_output(["/bin/bash", "-c", x]).decode("utf-8")
skip = ["%F", "%U", "%f", "%u"]; trim = ["chrome", "chromium", "nautilus"]

def apply(command):
    if "libreoffice" in command:
        proc = [l.split()[0] for l in get("ps -u "+user).splitlines() if "soffice.bin" in l]
        module = command.split("--")[-1]
        time.sleep(0.1)
        try:
            ws = sum([[w.split()[0] for w in get("wmctrl -lp").splitlines() if process in w and module in w.lower()] for process in proc], [])[0]
            subprocess.call(["wmctrl", "-ia", ws])
        except IndexError:
            subprocess.Popen(["/bin/bash", "-c", command+"&"])
    else:
        check = command.split("/")[-1][:14]
        proc = [p.split()[0] for p in get("ps -u "+user).splitlines() if check in p]
        time.sleep(0.5)
        try:
            ws = sum([[w.split()[0] for w in get("wmctrl -lp").splitlines() if process in w] for process in proc], [])
            if command == "nautilus":
                real_window = [w for w in ws if "_NET_WM_WINDOW_TYPE_NORMAL" in get("xprop -id "+w)][0]
            else:
                real_window = ws[0]
            subprocess.call(["wmctrl", "-ia", real_window])
        except IndexError:
            subprocess.Popen(["/bin/bash", "-c", command+"&"])
# default directories of .desktop files; globally, locally, LibreOffice- specific when separately installed
globally = "/usr/share/applications"; locally = os.environ["HOME"]+"/.local/share/applications"; lo_dir = "/opt/libreoffice4.4/share/xdg"
# create list of .desktop files; local ones have preference
local_files = [it for it in os.listdir(locally) if it.endswith(".desktop")]
global_files = [it for it in os.listdir(globally) if it.endswith(".desktop")]
lo_spec = [it for it in os.listdir(lo_dir) if it.endswith(".desktop")] if os.path.exists(lo_dir) else []
for f in [f for f in local_files if f in global_files]:
    global_files.remove(f)
for f in [f for f in local_files if f in lo_spec]:
    lo_spec.remove(f)
dtfiles = [globally+"/"+f for f in global_files]+[locally+"/"+f for f in local_files]+[lo_dir+"/"+f for f in lo_spec]
# create list of application names / commands
valid = []
for f in dtfiles:
    content = open(f).read()
    if all(["NoDisplay=true" not in content,"Exec=" in content]):
        lines = content.splitlines()
        name = [l.replace("Name=", "") for l in lines if "Name=" in l][0]
        command = [l.replace("Exec=", "") for l in lines if all(["Exec=" in l, not "TryExec=" in l])][0]
        valid.append((name, command))
valid.sort(key=lambda x: x[0])
# create zenity list + window
list_items = '"'+'" "'.join([f[0] for f in valid])+'"'
proposed = 'zenity --list --text "Type one or more characters... " --column="Application List" '+\
           '--title="Dash the Second" --height 450 --width 300 '+list_items
try:
    choice = subprocess.check_output(["/bin/bash", "-c", proposed]).decode("utf-8").strip().split("|")[0]
    command = [r[1] for r in valid if r[0] == choice][0]
    # command fixes:
    for s in skip:
        command = command.replace(" "+s, "")
    for t in trim:
        if t in command:
            command = t
    apply(command)
except subprocess.CalledProcessError:
    pass

Comment utiliser

Le script doit installer wmctrl:

Sudo apt-get install wmctrl

Ensuite:

  1. Collez le script ci-dessus dans un fichier vide, enregistrez-le sous le nom dash_alternative.py
  2. Ajoutez-le à une combinaison de touches de raccourci: Choisissez: Paramètres système> "Clavier"> "Raccourcis"> "Raccourcis personnalisés". Cliquez sur le "+" et ajoutez la commande:

    python3 /path/to/dash_alternative.py
    

Explication

Lorsque le script est exécuté, il répertorie toutes les applications, représentées dans /usr/share/applications. Il recherche les fichiers .dektop, créant une liste de tous les noms d'application (de la première ligne "Name =") et de la commande permettant d'exécuter l'application (de la première ligne "Exec =").

Ensuite, une liste Zenity est créée, présentant toutes les applications de manière triée.

Chaque fois qu'une application est sélectionnée, le script recherche dans la liste des processus en cours d'exécution si l'application est en cours d'exécution. Si c'est le cas, la fenêtre correspondante est levée. Sinon, une nouvelle instance est ouverte.

Remarques

  1. Pour exécuter le script sur 12.04 (puisque la question initiale a été marquée 12.04, il suffit de changer Shebang en #!/usr/bin/env python et de l'exécuter à l'aide de la commande

    python /path/to/dash_alternative.py
    
  2. Pour autant que je l'ai testé, le script fonctionne bien. Commandes et leurs noms de processus correspondants (non-correspondants) (par exemple, LibreOffice <> soffice.bin), différents types de fenêtres (nautilus a plusieurs types de fenêtres différents, en plus des fenêtres "réelles"), plusieurs pids par application (Chromium, Google-chrome) peut provoquer des exceptions, que j'ai corrigées dans les exemples ci-dessus. Si quelqu'un rencontre un problème, merci de le mentionner.

2. Supplémentaire: définissez-le comme une alternative au "vrai" tableau de bord pour l'exécution d'applications

  1. Copiez et sécurisez le script comme mentionné ci-dessus
  2. Enregistrez l'icône ci-dessous (clic droit> safe as) sous le nom dash_alternative.png

    enter image description here

  3. Copiez le code ci-dessous dans un fichier vide, enregistrez-le dans ~/.local/share/applications sous le nom dash_thesecond.desktop. Définissez les chemins corrects pour /path/to/dash_alternative.py (le script) et /path/to/dash_alternative.png (l'icône)

    [Desktop Entry]
    Name=Dash the Second
    Exec=python3 /path/to/dash_alternative.py
    Icon=/path/to/dash_alternative.png
    Type=Application
    Hidden=false
    
  4. Faites glisser le fichier .desktop sur le lanceur:

4
Jacob Vlijm

Pour launcher (le panneau vertical situé à gauche de l'écran), il s'agit déjà du comportement par défaut, car il s'agit de l'interface de commutation de tâches.

Pour le tiret (le gros bit qui s'ouvre lorsque vous cliquez sur le logo Ubuntu), il n'y a aucun moyen de changer le comportement de cette manière, sans une modification supposée importante du code source lui-même.

Cependant, certaines applications peuvent déjà le faire, car elles sont conçues pour se comporter de cette façon. Toutes les applications ne sont pas et ne doivent pas nécessairement être mises en œuvre de cette manière.

Une autre caractéristique cependant, si vous ouvrez la fenêtre avec Super+Wet commencez à taper un nom d’application, les fenêtres de cette application seront les seules affichées.

0
dobey