Avvia l'app solo se non è già aperta


16

Vorrei imitare l'uso di Alfred su Mac OS X, dove se provi ad aprire un'app dopo averla cercata, si aprirà una nuova finestra solo se il programma non è già in esecuzione, altrimenti si focalizzerà sul istanza attualmente in esecuzione di tale applicazione. Esiste un modo per modificare il comportamento predefinito del programma di avvio per verificarlo prima di aprire una nuova finestra?


Anche @pidge Per fare ciò non sarebbe difficile, ma influenzerebbe anche il comportamento "apri con" del tasto destro. Immagino che sia un effetto collaterale inaccettabile.
Jacob Vlijm,

1
Penso che dovresti essere in grado di creare uno script in grado di verificare se un processo specifico è già in esecuzione e decidere se avviare un nuovo processo o focalizzare l'attenzione sulla finestra esistente. Sfortunatamente, non sono ancora molto bravo nello scripting ... Ma @JacobVlijm è noto come un ragazzo con script per ogni scopo;) Dovresti sostituire tutti i lanciatori originali con il rispettivo script. Non sono sicuro che tu voglia / possa farlo - Non vorrei ...
Byte Commander

2
Se segui il percorso dello script, puoi utilizzare questo script come punto di partenza. L'ho scritto inizialmente per LXDE / Openbox, ma dovrebbe funzionare anche in Unity. Maggiori informazioni sullo script e il suo utilizzo qui .
Glutanimate,

1
@ByteCommander era esattamente quello che avevo in mente. Potresti persino sostituire lo script con i comandi nei .desktopfile. Se si sostituisce il comando nel .desktopfile, tuttavia, il tasto destro del mouse su Apri con opzione viene interrotto.
Jacob Vlijm,

1
Per quale ambiente desktop?
j0h

Risposte:


6

Aggiornamento 7 aprile: una versione diversa aggiunta e trovata Albert, vedi aggiornamento e Bonus qui sotto !!!

Per quanto riguarda la funzionalità del trattino : è stato chiesto " Esiste un modo per modificare il comportamento predefinito del programma di avvio per verificarlo prima di aprire una nuova finestra ". La risposta di base è, no, come utente normale non hai modo di aggiungere quel comportamento al trattino. Tuttavia, se ci fosse uno sviluppatore dell'ambito di unità che sarebbe disposto a implementarlo, potresti avvicinarti a loro o svilupparne uno tu stesso se hai determinazione e voglia di imparare. Le mie capacità di programmazione sono molto modeste, quindi uso come scripting shell shell e il front-end grafico disponibile per gli script.

Informazioni correlate

Post originale:

Ho scritto una sceneggiatura che utilizza il dialogo zenity e wmctrl per ottenere ciò che hai chiesto. Si noti che questo è uno script grafico, il che significa che funzionerà solo con Windows, nella GUI, e non funzionerà se si tenta di avviare qualcosa in tty. Inoltre, da quello che capisco Alfred fa esattamente la stessa cosa. È possibile creare un collegamento sul desktop ad esso o il collegamento di avvio ad esso, come descritto qui e qui .

Il copione:

#!/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

Note a margine: nella versione precedente, lo script utilizzava echo $ ?, per verificare se le espressioni precedenti uscivano correttamente. Come suggerito da Muru (dalla modifica), ho cambiato il codice in una versione un po 'più compatta, quindi ti suggerisco di dare un'occhiata alla versione precedente e alla corrente.

Inoltre, in precedenza wmctrl -a $MYPROGnon funzionava con i test di google-chrome o chromium-browser; per qualche stupida ragione alcuni programmi hanno la proprietà WM_CLASS della finestra maiuscola, mentre il programma come elencato dpkg --get-selectionsè in minuscolo (basta leggere man wmctrled eseguire wmctrl -lx, lo saprai). Aggiungendo che -ax dovrebbe occuparsene. La sceneggiatura fa apparire la finestra di cromo già aperta come dovrebbe

Un'altra cosa - wmctlr è alquanto strano in quanto a volte ha bisogno di un ritardo (ha avuto esperienza con esso in un altro script), quindi ho dovuto aggiungere una sleep 1riga. In precedenza sarebbe stato un po 'acceso e spento con Firefox, ma ora funziona a meraviglia.

La sceneggiatura in azione

Nell'animazione qui sotto puoi vedere che alla prima esecuzione dello script, c'è un'istanza di firefox aperta e gli script passano su quella finestra; nel secondo test, apro una nuova istanza di google-chrome, che non è stata aperta in precedenza. (Nota a margine: se sei curioso del desktop, a proposito, questo è openbox con il dock cairo)

Per suggerimento nei commenti, animazione incorporata rimossa, solo link pubblicato. Segnala se è rotto per favore! http://i.stack.imgur.com/puuPZ.gif

Aggiornamento, 7 aprile

Ho migliorato un po 'lo script per rendere tutti i programmi elencati nella casella di inserimento a discesa di zenity. Ora l'utente non deve memorizzare ciascun programma, ma può semplicemente scorrere un elenco di essi usando i tasti freccia o semplicemente aprire il menu a discesa. Inoltre, questa versione migliorata genera finestre non per nome, ma per id finestra, che offre prestazioni molto migliori. Nota, il modo in cui passo attraverso i file .desktop è un po 'ridondante, usando due volte il comando cut, ma dal momento che il mio script-fu non è poi così buono, questo è tutto ciò che posso fare. Suggerimenti di miglioramento sono ben accetti!

#!/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

inserisci qui la descrizione dell'immagine

Bonus:

In realtà ho trovato Albert , che è la versione Linux di Alfred, ma non l'ho provato da solo. Vale la pena dare un'occhiata però. Tuttavia, come Jacob ha già notato, è ancora difettoso.

Esiste un'app chiamata Gnome-Do, che appare graficamente simile ad Alfred, tuttavia non ha le stesse funzionalità di questo script.

inserisci qui la descrizione dell'immagine

Fammi sapere se ti piace questo script, se c'è qualcosa che deve essere riparato e non dimenticare di votare la risposta se lo trovi utile


A proposito, nota come scrivo i nomi dei programmi, esattamente come elencato in dpkg --get-selectons. Avviare libreoffice writer digitando "writer" non funzionerà, ma potresti creare un link simbolico nella cartella ~ / bin, / bin o / usr / bin o utilizzare l'alias in .bashrc o .profile.
Sergiy Kolodyazhnyy,

Nota anche che avrai bisogno di installare wmctl, che non è di default, ma piuttosto utile. L'ho anche usato per fare questo
Sergiy Kolodyazhnyy il

Potresti sostituire l'animazione con un'immagine, che si collega all'annimazione? Il mio browser continua a "caricare" la pagina, quindi non riesco ad aggiornarla. (e l'annullamento non viene eseguito :))
Jacob Vlijm,

Grazie! Il collegamento funziona bene in Chrome, non in Firefox.
Jacob Vlijm,

@JacobVlijm Ugh, così fa. Non sono sicuro del motivo per cui Firefox si rifiuta di riprodurlo. È solo un link imgur a ciò che ho caricato originariamente
Sergiy Kolodyazhnyy il

5

1. Tratteggia il secondo

Di seguito uno script che può essere utilizzato come alternativa a Dash, quando si tratta di eseguire applicazioni come descritto nella domanda.

Esiste di una finestra con le stesse funzionalità di Dash; se si digita uno o più caratteri dell'applicazione, l'applicazione verrà visualizzata nell'elenco. Premere Enterper avviare o aumentare l'applicazione, a seconda che sia già in esecuzione o meno.

Puoi chiamarlo da una combinazione di tasti di scelta rapida o impostare un'icona nel programma di avvio per usarlo in modo simile a Dash (vedi più avanti) o entrambi.

inserisci qui la descrizione dell'immagine

Il copione

#!/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

Come usare

Lo script deve essere wmctrlinstallato:

sudo apt-get install wmctrl

Poi:

  1. Incolla lo script sopra in un file vuoto, salvalo come dash_alternative.py
  2. Aggiungilo a una combinazione di tasti di scelta rapida: Scegli: Impostazioni di sistema> "Tastiera"> "Scorciatoie"> "Scorciatoie personalizzate". Fai clic su "+" e aggiungi il comando:

    python3 /path/to/dash_alternative.py
    

Spiegazione

Quando viene eseguito lo script, elenca tutte le applicazioni, rappresentate in /usr/share/applications. Cerca i .dektopfile, creando un elenco di tutti i nomi delle applicazioni (dalla prima riga "Nome =") e il comando per eseguire l'applicazione (dalla prima riga "Exec =").

Successivamente, viene creato un elenco Zenity, che presenta tutte le applicazioni in modo ordinato.

Ogni volta che viene selezionata un'applicazione, lo script viene visualizzato nell'elenco dei processi in esecuzione se l'applicazione è in esecuzione. In tal caso, viene visualizzata la finestra corrispondente. In caso contrario, viene aperta una nuova istanza.

Appunti

  1. Per eseguire lo script su 12.04 (poiché la domanda originale è stata taggata, è 12.04sufficiente cambiare lo shebang #!/usr/bin/env pythoned eseguirlo dal comando

    python /path/to/dash_alternative.py
    
  2. Per quanto ho provato, lo script funziona bene. I comandi e i loro (non-) nomi di processo corrispondenti (ad es. LibreOffice<> soffice.bin), Diversi tipi di finestra ( nautilusha diversi tipi di finestra, oltre a finestre "reali"), più pid per applicazione ( Chromium, Google-chrome) possono causare eccezioni, che ho corretto negli esempi sopra. Se qualcuno incontra un problema, per favore, menzionalo.

2. Aggiuntivo: impostandolo come alternativa al "vero" Dash per le applicazioni in esecuzione

  1. Copia e salva lo script come indicato sopra
  2. Salvare l'icona in basso (tasto destro> sicuro come) come dash_alternative.png

    inserisci qui la descrizione dell'immagine

  3. Copia il codice qui sotto in un file vuoto, salvalo ~/.local/share/applicationscome dash_thesecond.desktop. Imposta i percorsi corretti per /path/to/dash_alternative.py(lo script) e /path/to/dash_alternative.png(l'icona)

    [Desktop Entry]
    Name=Dash the Second
    Exec=python3 /path/to/dash_alternative.py
    Icon=/path/to/dash_alternative.png
    Type=Application
    Hidden=false
    
  4. Trascina il .desktopfile sul programma di avvio:


1
Bello sapere che esiste un'intera cartella di file .desktop! Mi chiedevo come vengono elencate le applicazioni native e installate per nome anziché i comandi. Ottimo lavoro lì!
Sergiy Kolodyazhnyy,

@Serg Grazie! e lo stesso per te :). C'è anche una directory locale per il .desktopfile: ~/.local/share/applications. Ho pensato di limitare la ricerca alle applicazioni installate a livello globale.
Jacob Vlijm,

Jacob, non conosco Python, ma forse questo ti sarà utile per migliorare la tua sceneggiatura trasformandola in un ambito unitario. La mia comprensione è che questo è l'unico modo per modificare la funzionalità del trattino esattamente come vuole OP
Sergiy Kolodyazhnyy

@Serg Grazie! questo è un post interessante, lo vedremo sicuramente bene!
Jacob Vlijm,

0

Per il programma di avvio (il pannello verticale sul lato sinistro dello schermo), questo è già il comportamento predefinito, in quanto è l'interfaccia di commutazione delle attività.

Per il trattino (il bit grande che si apre facendo clic sul logo Ubuntu), non c'è modo di cambiare il comportamento in questo modo, senza una presumibilmente significativa modifica al codice sorgente stesso.

Tuttavia, alcune app potrebbero già farlo, poiché sono progettate per comportarsi in questo modo. Tuttavia, tutte le app non sono e non devono necessariamente essere implementate in questo modo.

Tuttavia, se si apre la finestra diffusa con Super+ We si inizia a digitare il nome di un'applicazione, le finestre per tale applicazione saranno le uniche visualizzate.


In realtà ho trovato la versione Linux di ciò che OP voleva, vedere il mio post, la sezione bonus. A quanto pare qualcun altro ha avuto l'idea di portare Alfred su Linux
Sergiy Kolodyazhnyy

1
@Serg, per favore, prova Albert; Albert ha ancora il "bug LibreOffice", il "bug Chromium" e il "bug Chrome". Anche il "Bug dei file" ... Albert semplicemente apre sempre una nuova istanza di quelle applicazioni. LibreOffice semplicemente non funziona affatto. Inoltre, nei commenti sotto il tuo link puoi trovare una serie di problemi.
Jacob Vlijm,

@Serg No, hai trovato una soluzione alternativa, aggiungendo un ulteriore software in esecuzione in background, che fornisce un'esperienza utente completamente diversa e richiede una riqualificazione di come trovare le applicazioni. La domanda posta era come far funzionare questo lavoro nel dash Unity. Potresti essere in grado di ottenere una funzionalità simile al di fuori di Unity stesso, ma l'unico modo per cambiare Unity per farlo è cambiare il codice sorgente.
dobey

@dobey Bene, è vero; la modifica della funzionalità del trattino è fuori dalla nostra portata, quindi. . . Devo fare con quello che abbiamo un disponibile, giusto? A meno che non ci sia uno sviluppatore che sarebbe disposto a codificare un ambito unitario con tale funzionalità. . .
Sergiy Kolodyazhnyy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.