Como posso executar um programa na inicialização, minimizado?

16

Eu só quero que o Telegram seja executado e eu o adicionei aos aplicativos de inicialização. O ponto é que eu preciso que seja minimizado. Algum comando?

    
por Hossein Soltanloo 19.08.2015 / 07:28

4 respostas

28

Iniciando um aplicativo minimizado

Iniciar um aplicativo de maneira minimizada exige dois comandos:

  • iniciando o aplicativo
  • minimize sua janela

Portanto, o comando ou script precisa ser "inteligente"; o segundo comando deve aguardar a exibição da janela do aplicativo.

Solução geral para iniciar um aplicativo minimizado

O script abaixo faz isso e pode ser usado como uma solução geral para iniciar um aplicativo de maneira minimizada. Basta executá-lo na sintaxe:

<script> <command_to_run_the_application> <window_name>

O 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

Como usar

O script precisa dos dois wmctrl e xdotool :

sudo apt-get install wmctrl xdotool

Então:

  1. Copie o script em um arquivo vazio, salve-o como startup_minimizd.py
  2. Teste: execute o script com (por exemplo) gedit o comando:

    python3 /path/to/startup_minimizd.py gedit gedit
    
  3. Se tudo funcionar bem, adicione o comando (para seu aplicativo) a Startup Applications

Explicação

  • O script inicializa o aplicativo, executando o comando que você deu como primeiro argumento
  • Em seguida, o script verifica a lista de janelas (com a ajuda de wmctrl ) para as janelas, nomeadas após seu segundo argumento.
  • Se a janela aparecer, ela será imediatamente minimizada com a ajuda de xdotool Para evitar um loop infinito se a janela não aparecer por algum motivo, o script pratica um limite de tempo de 30 segundos para que a janela apareça.

Nota

Não é necessário mencionar que você pode usar o script para vários aplicativos de uma só vez, já que você o executa com argumentos fora do script.

EDITAR

reconhecendo a janela pelo seu pid

Se o título da janela for inseguro ou variável, ou houver risco de conflito de nomes no nome da janela, usar o pid é um método mais confiável para usar.

O script abaixo é baseado no uso do pid do aplicativo, como na saída de wmctrl -lp e ps -ef .

A configuração é praticamente a mesma, mas o título da janela não é necessário nesta versão, então o comando para executá-la é:

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

Assim como o primeiro script, ele precisa dos dois wmctrl e xdotool

O 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)

Anote no segundo script

Embora, em geral, a segunda versão deva ser mais confiável, nos casos em que o aplicativo é iniciado por um script wrapper, o pid do comando será diferente do aplicativo que é finalmente chamado.

Nesses casos, recomendo usar o primeiro script.


EDIT2 uma versão específica do script para o Steam

Conforme solicitado em um comentário, abaixo de uma versão, feita especificamente para a inicialização do STEAM, foi minimizada.

Por que uma versão específica para o Steam?

Acontece que Steam se comporta bem diferente de um aplicativo "normal":

  • Acontece que Steam não executa um pid, mas não menos que (no meu teste) oito!
  • Steam é executado na inicialização com pelo menos duas janelas (uma janela semelhante a um splash), mas às vezes uma janela de mensagem adicional é exibida.
  • O Windows do Steam tem pid 0 , o que é um problema no script como era.
  • Depois que a janela principal é criada, a janela é levantada uma segunda vez depois de um segundo, portanto, uma minimização única não funcionará.

Esse comportamento excepcional de Steam pede uma versão especial do script, que é adicionada abaixo. O script é iniciado em Steam e, durante 12 segundos, fica de olho em todas as novas janelas do WM_CLASS correspondente, verificando se elas estão minimizadas. Se não, o script garante que eles serão.

Como o script original, este precisa que wmctrl e xdotool estejam instalados.

O 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)

Para usá-lo

  • Basta copiá-lo em um arquivo vazio, salve-o como runsteam_minimized.py
  • Execute-o pelo comando:

    python3 /path/to/runsteam_minimized.py
    
por Jacob Vlijm 19.08.2015 / 13:56
3

É bom ter os scripts fornecidos pelo user72216 e Sergey como soluções gerais para o problema, mas às vezes o aplicativo que você deseja iniciar minimizado já tem um switch que fará o que você quiser.

Aqui estão alguns exemplos com as sequências de comandos do programa de inicialização correspondentes:

  • Telegrama (desde a versão 0.7.10) tem a opção -startintray : <path-to-Telegram>/Telegram -startintray
  • O Steam tem a opção -silent : /usr/bin/steam %U -silent
  • A transmissão tem a opção --minimized : /usr/bin/transmission-gtk --minimized

No Unity, esses aplicativos começam a ser minimizados como ícones na barra de menu superior, e não como ícones no inicializador, embora o ícone de inicialização normal ainda apareça quando você começar a usar o aplicativo. Outras aplicações podem se comportar de maneira diferente.

    
por Francis Chin 24.09.2016 / 17:57
1

Se o programa está sendo fechado para a bandeja, pode-se realmente querer fechar a janela do programa na inicialização, em vez de minimizá-lo. Um exemplo de tal programa é o Viber. Neste caso, pode-se usar o seguinte 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

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

    
por Mykola Novik 03.12.2017 / 10:18
1

Eu peguei os scripts de Jacob e os modifiquei um pouco para torná-los mais universais.

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

As principais diferenças são:

  • O programa define o ID do grupo (GID) para o processo. Assim, todos os processos filhos e suas janelas podem ser facilmente encontrados
  • A opção
  • xdotool --sync é usada em vez de um loop while
  • Script permite passar argumentos para o programa

WAIT_TIME deve ser grande o suficiente para permitir que o programa bifurque seus processos filhos. No meu computador, é suficiente para grandes programas como o vapor. Aumente, se necessário.

Adição

A opção xdotool windowunmap pode funcionar bem com alguns aplicativos e programas de bandeja (a bandeja do linux mint, por exemplo), então aqui está uma versão alternativa do script para essas exceções.

#!/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)
    
por Sergey 16.08.2016 / 19:21