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

16

Je voudrais imiter l'utilisation d'Alfred sur Mac OS X, où si vous essayez d'ouvrir une application après l'avoir recherchée, elle n'ouvrira une nouvelle fenêtre que si le programme n'est pas déjà en cours d'exécution, sinon elle mettra l'accent 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?

Dan Jenson
la source
Aussi @pidge Pour ce faire, il ne serait pas difficile, mais cela affecterait également le comportement du clic droit "Ouvrir avec". Je suppose que c'est un effet secondaire inacceptable.
Jacob Vlijm
1
Je pense que vous devriez être en mesure de créer un script qui peut vérifier si un processus spécifique est déjà en cours d'exécution et décider soit de lancer un nouveau processus soit de donner le focus à la fenêtre existante. Malheureusement, je ne suis pas encore très bon en script ... Mais @JacobVlijm est connu comme un gars avec des scripts pour tous les usages;) Vous devrez cependant remplacer tous les lanceurs originaux par le script respectif. Je ne sais pas si vous voulez / pouvez le faire - je ne voudrais pas ...
Byte Commander
2
Si vous choisissez la route du script, vous pouvez utiliser ce script comme point de départ. Je l'ai écrit pour LXDE / Openbox au départ, mais cela devrait aussi fonctionner dans Unity. Plus d'informations sur le script et son utilisation ici .
Glutanimate le
1
@ByteCommander, c'est exactement ce que j'avais en tête. Vous pouvez même remplacer par script les commandes dans les .desktopfichiers. .desktopCependant, si vous remplacez la commande dans le fichier, le clic droit sur l'option Ouvrir avec est rompu.
Jacob Vlijm
1
Pour quel environnement de bureau?
j0h

Réponses:

6

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

Concernant la fonctionnalité de tiret : Vous avez demandé " Est-il possible de changer le comportement par défaut du lanceur pour vérifier cela avant d'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 de portée unitaire qui serait disposé à mettre en œuvre cela, vous pouvez les approcher ou en développer un vous-même si vous êtes résolu et disposé à apprendre. Mes compétences en codage sont très modestes, c'est pourquoi j'utilise le script shell et le frontal graphique disponible pour les scripts comme solution de contournement.

Information connexe

Message d'origine:

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. D'ailleurs, d'après ce que je comprends, Alfred fait exactement la même chose. Vous pouvez y créer un raccourci sur le bureau ou un raccourci de lancement, comme décrit ici et ici .

Le script:

#!/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 /ubuntu//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 tester si les expressions précédentes se terminaient correctement. Selon la suggestion de muru (de l'édition), j'ai changé le code pour une version un peu plus compacte, donc je vous suggère de jeter un œil à la version précédente et à la version actuelle.

En outre, auparavant wmctrl -a $MYPROG, ne fonctionnait pas avec les tests google-chrome ou chrome-browser; pour une raison stupide, certains programmes ont la propriété WM_CLASS de la fenêtre en majuscule, tandis que le programme tel que répertorié par dpkg --get-selectionsest en minuscules (il suffit de le lire man wmctrlet de l'exécuter wmctrl -lx, vous le saurez). L'ajout de -ax devrait prendre soin de cela. Le script affiche la fenêtre de chrome déjà ouverte comme il se doit

Une autre chose - wmctlr est quelque peu bizarre dans la mesure où il a parfois besoin d'un délai (avait de l'expérience avec un autre script), donc j'ai dû ajouter une sleep 1ligne. Auparavant, il était en quelque sorte allumé et éteint avec Firefox, mais fonctionne maintenant à merveille.

Le script en action

Dans l'animation ci-dessous, vous pouvez voir que lors de la première exécution du script, il y a une instance de firefox ouverte, et le script bascule sur cette fenêtre; lors du deuxième test, j'ouvre une nouvelle instance de google-chrome, qui n'a pas été ouverte auparavant. (Remarque: si vous êtes curieux au sujet du bureau, soit dit en passant, c'est openbox avec dock cairo)

Par suggestion dans les commentaires, animation intégrée supprimée, lien publié uniquement. Signalez s'il est cassé s'il vous plaît! http://i.stack.imgur.com/puuPZ.gif

Mise à jour, 7 avril

J'ai quelque peu amélioré le script pour rendre tous les programmes répertoriés dans la zone de liste déroulante de zenity. Maintenant, l'utilisateur n'a plus à 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. De plus, cette version améliorée lève les fenêtres non pas par nom, mais par identifiant de fenêtre, ce qui donne de bien meilleures performances. Remarque, la façon dont je parcours les fichiers .desktop est un peu redondante, en utilisant la commande cut deux fois, mais comme mon script-fu n'est pas si bon jusqu'à présent, 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 /ubuntu//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

entrez la description de l'image ici

Prime:

J'ai en fait 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 cependant. 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 elle n'a pas les mêmes fonctionnalités que ce script.

entrez la description de l'image ici

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

Sergiy Kolodyazhnyy
la source
Soit dit en passant, remarquez comment je tape les noms des programmes - exactement comme indiqué dans dpkg --get-selectons. Le lancement de libreoffice writer en tapant "writer" ne fonctionnera pas, mais vous pouvez créer un lien symbolique vers celui-ci dans votre dossier ~ / bin, / bin ou / usr / bin ou utiliser un alias dans .bashrc ou .profile.
Sergiy Kolodyazhnyy
Notez également que vous aurez besoin de wmctl installé, il ne vient pas par défaut, mais assez pratique. Je l'ai également utilisé pour faire cela
Sergiy Kolodyazhnyy
Pourriez-vous remplacer l'annimation par une image, reliant à l'annimation? Mon navigateur continue de «charger» la page, je ne peux donc pas la rafraîchir. (et l'annimation ne fonctionne pas :))
Jacob Vlijm
Merci! Le lien fonctionne bien dans Chrome, pas dans Firefox.
Jacob Vlijm
@JacobVlijm Ugh, c'est vrai. Je ne sais pas pourquoi firefox refuse de le jouer. C'est juste un lien imgur vers ce que j'ai initialement téléchargé
Sergiy Kolodyazhnyy
5

1. Dash the 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 d'une fenêtre avec la même fonctionnalité que Dash; si vous tapez un ou plusieurs caractères de l'application, l'application apparaîtra dans la liste. Appuyez sur Enterpour démarrer ou augmenter 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 lanceur pour l'utiliser de manière similaire à Dash (voir ci-dessous), ou les deux.

entrez la description de l'image ici

Le script

#!/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 être wmctrlinstallé:

sudo apt-get install wmctrl

Alors:

  1. Collez le script ci-dessus dans un fichier vide, enregistrez-le sous 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 .dektopfichiers, créant une liste de tous les noms d'applications (à partir de la première ligne "Name =") et la commande pour exécuter l'application (à partir de la première ligne "Exec =").

Par la suite, 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 regarde 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 ouverte. Sinon, une nouvelle instance est ouverte.

Remarques

  1. Pour exécuter le script le 12.04 (puisque la question d'origine a été balisée, 12.04changez simplement le shebang en #!/usr/bin/env pythonet exécutez-le par la commande

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

2. Supplémentaire: le définir comme une alternative au "vrai" Dash pour exécuter des applications

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

    entrez la description de l'image ici

  3. Copiez le code ci-dessous dans un fichier vide, enregistrez-le ~/.local/share/applicationssous 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 .desktopfichier sur le lanceur:

Jacob Vlijm
la source
1
Heureux de savoir qu'il existe un dossier complet de fichiers .desktop! Je me demandais comment les applications natives et apt-installées sont répertoriées par nom au lieu de commandes. Bon travail là-bas!
Sergiy Kolodyazhnyy
@Serg Merci! et la même chose pour toi :). Il y a aussi un répertoire local pour les .desktopfichiers: ~/.local/share/applications. Je pensais que je limiterais la recherche aux applications installées à l'échelle mondiale.
Jacob Vlijm
Jacob, je ne connais pas le python, mais peut - être que cela vous sera utile pour améliorer votre script en le transformant en portée d'unité. Je crois comprendre que c'est la seule façon de modifier la fonctionnalité du tableau de bord exactement comme OP le souhaite
Sergiy Kolodyazhnyy
@Serg Merci! c'est un article intéressant, je vais certainement y jeter un coup d'oeil!
Jacob Vlijm
0

Pour le lanceur (le panneau vertical sur le côté gauche de l'écran), c'est déjà le comportement par défaut, car c'est l'interface de changement de tâche.

Pour le tiret (le gros morceau 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 vraisemblablement significative 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. Cependant, toutes les applications ne sont pas et ne devraient pas nécessairement être implémentées de cette manière.

Cependant, si vous ouvrez la fenêtre étendue avec Super+ Wet commencez à saisir le nom d'une application, les fenêtres de cette application seront les seules affichées.

dobey
la source
En fait, j'ai trouvé la version Linux de ce que voulait OP, voir mon article, la section bonus. Apparemment, quelqu'un d'autre a eu une idée d'amener Alfred à Linux
Sergiy Kolodyazhnyy
1
@Serg, essayez Albert; Albert a toujours le "bug LibreOffice", le "bug Chrome" et le "bug Chrome". Même le "bug des fichiers" ... Albert ouvre simplement toujours une nouvelle instance de ces applications. LibreOffice ne fonctionne tout simplement pas du tout. En outre, dans les commentaires ci-dessous votre lien, vous pouvez trouver un certain nombre de problèmes.
Jacob Vlijm
@Serg Non, vous avez trouvé une solution de contournement, en ajoutant un logiciel supplémentaire fonctionnant en arrière-plan, qui offre une expérience utilisateur complètement différente et nécessite un recyclage pour trouver des applications. La question posée était de savoir comment avoir ce travail dans le tableau de bord Unity. Vous pouvez peut-être obtenir une fonctionnalité similaire en dehors d'Unity, mais la seule façon de modifier Unity pour ce faire est de modifier le code source.
dobey
@dobey Eh bien, c'est vrai; modifier la fonctionnalité du tableau de bord est hors de notre portée, donc. . .gotta faire avec ce que nous avons un disponible, non? Sauf s'il y a un développeur qui serait disposé à coder une étendue d'unité avec une telle fonctionnalité. . .
Sergiy Kolodyazhnyy