Come posso eseguire un programma all'avvio, ridotto al minimo?

16

Voglio solo che Telegram sia eseguito e l'ho aggiunto alle app di avvio. Il punto è che ho bisogno che sia ridotto al minimo. Qualche comando?

    
posta Hossein Soltanloo 19.08.2015 - 07:28

4 risposte

28

Avvio di un'applicazione ridotta a icona

Avviare un'applicazione in un modo minimizzato richiede due comandi:

  • avvio dell'applicazione
  • riduci la finestra

Pertanto, il comando o lo script deve essere "intelligente"; il secondo comando dovrebbe attendere l'effettiva visualizzazione della finestra dell'applicazione.

Soluzione generale per l'avvio di un'applicazione ridotta a icona

Lo script seguente lo fa e può essere usato come soluzione generale per avviare un'applicazione in modo minimizzato. Basta eseguirlo nella sintassi:

<script> <command_to_run_the_application> <window_name>

Lo script

#!/usr/bin/env python3
import subprocess
import sys
import time

subprocess.Popen(["/bin/bash", "-c", sys.argv[1]])
windowname = sys.argv[2]

def read_wlist(w_name):
    try:
        l = subprocess.check_output(["wmctrl", "-l"]).decode("utf-8").splitlines()
        return [w.split()[0] for w in l if w_name in w][0]
    except (IndexError, subprocess.CalledProcessError):
        return None

t = 0
while t < 30:
    window = read_wlist(windowname)
    time.sleep(0.1)
    if window != None:
        subprocess.Popen(["xdotool", "windowminimize", window])
        break
    time.sleep(1)
    t += 1

Come usare

Lo script richiede sia wmctrl che xdotool :

sudo apt-get install wmctrl xdotool

Quindi:

  1. Copia lo script in un file vuoto, salvalo come startup_minimizd.py
  2. Test - esegui lo script con (ad esempio) gedit il comando:

    python3 /path/to/startup_minimizd.py gedit gedit
    
  3. Se tutto funziona correttamente, aggiungi il comando (per l'applicazione) a Startup Applications

Spiegazione

  • Lo script avvia l'applicazione, eseguendo il comando che hai dato come primo argomento
  • Quindi lo script controlla l'elenco delle finestre (con l'aiuto di wmctrl ) per Windows, chiamato dopo il secondo argomento.
  • Se viene visualizzata la finestra, questa viene immediatamente ridotta con l'aiuto di xdotool Per evitare un ciclo infinito se la finestra potrebbe non apparire per qualche motivo, lo script applica un limite di tempo di 30 secondi affinché la finestra appaia.

Nota

Non c'è bisogno di menzionare che puoi usare lo script per più applicazioni contemporaneamente, dato che lo esegui con argomenti al di fuori dello script.

Modifica

riconoscere la finestra dal suo pid

Se il titolo della finestra non è sicuro o variabile, o c'è il rischio di conflitti tra nomi nel nome della finestra, usare pid è un metodo più affidabile da usare.

Lo script sottostante si basa sull'utilizzo del pid dell'applicazione, come nell'output di wmctrl -lp e ps -ef .

L'installazione è praticamente la stessa, ma il titolo della finestra non è necessario in questa versione, quindi il comando per eseguirlo è:

python3 /path/to/startup_minimizd.py <command_to_run_application>

Proprio come il primo script, ha bisogno sia di wmctrl che di xdotool

Lo script

#!/usr/bin/env python3
import subprocess
import sys
import time

command = sys.argv[1]
command_check = command.split("/")[-1]

subprocess.Popen(["/bin/bash", "-c", command])

t = 1
while t < 30:
    try:
        w_list = [l.split() for l in subprocess.check_output(["wmctrl", "-lp"]).decode("utf-8").splitlines()]
        proc = subprocess.check_output(["pgrep", "-f", command_check]).decode("utf-8").strip().split()
        match = sum([[l[0] for l in w_list if p in l] for p in proc], [])
        subprocess.Popen(["xdotool", "windowminimize", match[0]])
        break
    except (IndexError, subprocess.CalledProcessError):
        pass
    t += 1
    time.sleep(1)

Nota sul secondo script

Anche se in generale la seconda versione dovrebbe essere più affidabile, nei casi in cui l'applicazione viene avviata da uno script wrapper, il pid del comando sarà diverso dall'applicazione che viene infine chiamata.

In questi casi, consiglio di utilizzare il primo script.

EDIT2 una versione specifica dello script per Steam

Come richiesto in un commento, al di sotto di una versione, appositamente creato per l'avvio di STEAM ridotto a icona.

Perché una versione specifica per Steam?

Risulta che Steam si comporta in modo abbastanza diverso da un'applicazione "normale":

  • Si scopre che Steam non esegue un pid, ma non meno poi (nel mio test) otto!
  • Steam viene eseguito all'avvio con almeno due finestre (una finestra di tipo splash), ma a volte viene visualizzata una finestra di messaggio aggiuntiva.
  • Windows di Steam ha pid 0 , che è un problema nello script com'era.
  • Una volta creata la finestra principale, la finestra viene sollevata una seconda volta dopo circa un secondo, quindi una riduzione singola non verrà eseguita.

Questo comportamento eccezionale di Steam richiede una versione speciale dello script, che viene aggiunta di seguito. Lo script inizia Steam e durante 12 secondi tiene d'occhio tutte le nuove finestre del WM_CLASS corrispondente, controllando se sono ridotte al minimo. Altrimenti, lo script si assicurerà che lo saranno.

Come lo script originale, questo ha bisogno di wmctrl e xdotool da installare.

Lo script

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

command = "steam"
subprocess.Popen(["/bin/bash", "-c", command])

def get(cmd):
    return subprocess.check_output(cmd).decode("utf-8").strip()

t = 0

while t < 12:
    try:
        w_list = [l.split()[0] for l in get(["wmctrl", "-l"]).splitlines()]
        for w in w_list:
            data = get(["xprop", "-id", w])
            if all(["Steam" in data, not "_NET_WM_STATE_HIDDEN" in data]):
                subprocess.Popen(["xdotool", "windowminimize", w])
    except (IndexError, subprocess.CalledProcessError):
        pass

    t += 1
    time.sleep(1)

Per usarlo

  • Copia semplicemente in un file vuoto, salvalo come runsteam_minimized.py
  • Eseguilo con il comando:

    python3 /path/to/runsteam_minimized.py
    
risposta data Jacob Vlijm 19.08.2015 - 13:56
3

È bello avere gli script forniti dall'utente72216 e Sergey come soluzioni generali al problema, ma a volte l'applicazione che si desidera ridurre a icona ha già un interruttore che farà ciò che si desidera.

Ecco alcuni esempi con le corrispondenti stringhe di comando del programma di avvio:

  • Telegram (dalla versione 0.7.10) ha l'opzione -startintray : <path-to-Telegram>/Telegram -startintray
  • Steam ha l'opzione -silent : /usr/bin/steam %U -silent
  • La trasmissione ha l'opzione --minimized : /usr/bin/transmission-gtk --minimized

In Unity, queste applicazioni iniziano a essere ridotte a icona come icone nella barra dei menu in alto anziché come icone sul programma di avvio, anche se l'icona di avvio normale verrà visualizzata non appena inizierai a utilizzare l'applicazione. Altre applicazioni possono comportarsi in modo diverso.

    
risposta data Francis Chin 24.09.2016 - 17:57
1

Se il programma viene chiuso sul vassoio, in realtà si potrebbe voler chiudere la finestra del programma all'avvio invece di ridurlo al minimo. Un esempio di tale programma è Viber. In questo caso si potrebbe usare il seguente script start_closed.sh :

#!/bin/bash

# Check that there is only one input argument
if [[ $# -gt 1 ]]; then
echo "Usage: $0 <program-to-start>"
exit 1
fi

$1 &                               # Start program passed in first argument
pid=$!                             # Get PID of last started program
xdotool search --sync --pid $pid | # Wait for window with PID to appear...
xargs wmctrl -i -c                 # ...and close it

Utilizzo: <path-to-script> <program-to-start>

    
risposta data Mykola Novik 03.12.2017 - 10:18
1

Ho preso gli script di Jacob e li ho modificati un po 'per renderne uno più universale.

#!/usr/bin/python

import os
import subprocess
import sys
import time
import signal

WAIT_TIME = 10


def check_exist(name):
    return subprocess.Popen("which "+name,
                            shell=True,
                            stdout=subprocess.PIPE
                            ).stdout.read().rstrip("-n")


def killpid(pidlist):
    for pid in pidlist:
        args = ["xdotool",
                "search",
                "--any",
                "--pid",
                pid,
                "--name",
                "notarealprogramname",
                "windowunmap",
                "--sync",
                "%@"]
        subprocess.Popen(args)


def killname(name):
    args = ["xdotool",
            "search",
            "--any",
            "--name",
            "--class",
            "--classname",
            name,
            "windowunmap",
            "--sync",
            "%@"]
    subprocess.Popen(args)


sys.argv.pop(0)

if check_exist(sys.argv[0]) == "":
    sys.exit(1)
if check_exist("xdotool") == "":
    sys.stderr.write("xdotool is not installed\n")
    sys.exit(1)
if check_exist("wmctrl") == "":
    sys.stderr.write("wmctrl is not installed\n")
    sys.exit(1)

try:
    prog = subprocess.Popen(sys.argv, preexec_fn=os.setsid)
except OSError, e:
    sys.exit(1)

time.sleep(WAIT_TIME)
idlist = subprocess.Popen("pgrep -g " + str(prog.pid),
                          shell=True,
                          stdout=subprocess.PIPE
                          ).stdout.read().splitlines()

ps1 = os.fork()
if ps1 > 0:
    ps2 = os.fork()

if ps1 == 0:  # Child 1
    os.setpgid(os.getpid(), os.getpid())
    killpid(idlist)
    sys.exit(0)
elif ps2 == 0:  # Child 2
    killname(os.path.basename(sys.argv[0]))
    sys.exit(0)
elif ps1 > 0 and ps2 > 0:  # Parent
    time.sleep(WAIT_TIME)
    os.killpg(os.getpgid(int(ps1)), signal.SIGTERM)
    os.kill(ps2, signal.SIGTERM)
    os.waitpid(ps1, 0)
    os.waitpid(ps2, 0)
    sys.exit(0)
else:
    exit(1)

Le principali differenze sono:

  • Il programma imposta l'ID di gruppo (GID) per il processo. Pertanto, tutti i processi figlio e le loro finestre possono essere facilmente trovati
  • l'opzione xdotool --sync viene utilizzata al posto di un ciclo while
  • Script consente di passare argomenti al programma

WAIT_TIME dovrebbe essere impostato in modo tale da consentire al programma di eseguire il fork dei suoi processi figli. Sul mio computer è abbastanza per grandi programmi come il vapore. Aumentalo, se necessario.

Aggiunta

L'opzione

xdotool windowunmap può funzionare in modo funky con alcune applicazioni e programmi vassoio (ad esempio, il vassoio di linux di Linux), quindi ecco una versione alternativa dello script per tali eccezioni.

#!/usr/bin/python

import os
import subprocess
import sys
import time
import signal

WAIT_TIME = 10


def check_exist(name):
    return subprocess.Popen("which "+name,
                            shell=True,
                            stdout=subprocess.PIPE
                            ).stdout.read().rstrip("-n")


def killpid(pidlist):
    for pid in pidlist:
        args = ["xdotool",
                "search",
                "--sync",
                "--pid",
                pid]
        for i in subprocess.Popen(args,
                                  stdout=subprocess.PIPE).\
                stdout.read().splitlines():
            if i != "":
                subprocess.Popen("wmctrl -i -c " +
                                 hex(int(i)), shell=True)


def killname(name):
    args = ["xdotool",
            "search",
            "--sync",
            "--any",
            "--name",
            "--class",
            "--classname",
            name]
    for i in subprocess.Popen(args,
                              preexec_fn=os.setsid,
                              stdout=subprocess.PIPE)\
            .stdout.read().splitlines():
        if i != "":
            subprocess.Popen("wmctrl -i -c " + hex(int(i)),
                             shell=True)


sys.argv.pop(0)

if check_exist(sys.argv[0]) == "":
    sys.exit(1)
if check_exist("xdotool") == "":
    sys.stderr.write("xdotool is not installed\n")
    sys.exit(1)
if check_exist("wmctrl") == "":
    sys.stderr.write("wmctrl is not installed\n")
    sys.exit(1)


try:
    prog = subprocess.Popen(sys.argv, preexec_fn=os.setsid)
except OSError, e:
    sys.exit(1)

time.sleep(WAIT_TIME)
idlist = subprocess.Popen("pgrep -g " + str(prog.pid),
                          shell=True,
                          stdout=subprocess.PIPE
                          ).stdout.read().splitlines()

ps1 = os.fork()
if ps1 > 0:
    ps2 = os.fork()

if ps1 == 0:  # Child 1
    os.setpgid(os.getpid(), os.getpid())
    killpid(idlist)
    sys.exit(0)
elif ps2 == 0:  # Child 2
    killname(os.path.basename(sys.argv[0]))
    sys.exit(0)
elif ps1 > 0 and ps2 > 0:  # Parent
    time.sleep(WAIT_TIME)
    os.killpg(os.getpgid(int(ps1)), signal.SIGTERM)
    os.kill(ps2, signal.SIGTERM)
    os.waitpid(ps1, 0)
    os.waitpid(ps2, 0)
    sys.exit(0)
else:
    exit(1)
    
risposta data Sergey 16.08.2016 - 19:21

Leggi altre domande sui tag