Eu só quero que o Telegram seja executado e o adicionei aos aplicativos de inicialização. O ponto é que eu preciso que seja minimizado. Algum comando?
Eu só quero que o Telegram seja executado e o adicionei aos aplicativos de inicialização. O ponto é que eu preciso que seja minimizado. Algum comando?
Respostas:
A inicialização de um aplicativo de maneira minimizada requer dois comandos:
Portanto, o comando ou script precisa ser "inteligente"; o segundo comando deve esperar que a janela do aplicativo seja exibida.
O script abaixo faz isso e pode ser usado como uma solução geral para inicializar um aplicativo de maneira minimizada. Basta executá-lo na sintaxe:
<script> <command_to_run_the_application> <window_name>
#!/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
O script precisa de ambos wmctrl
e xdotool
:
sudo apt-get install wmctrl xdotool
Então:
startup_minimizd.py
Teste - execute o script com (por exemplo) gedit
o comando:
python3 /path/to/startup_minimizd.py gedit gedit
Startup Applications
wmctrl
) para janelas, com o nome do seu segundo argumento.xdotool
Para evitar um loop sem fim, se a janela não aparecer por algum motivo, o script pratica um limite de tempo de 30 segundos para a janela aparecer.Não é necessário mencionar que você pode usar o script para vários aplicativos ao mesmo tempo, desde que você o execute com argumentos fora do script.
Se o título da janela for incerto ou variável, ou se houver um risco de conflito de nome no nome da janela, usar o pid
é um método mais confiável de usar.
O script abaixo é baseado no uso do pid do aplicativo, como na saída de ambos wmctrl -lp
e ps -ef
.
A configuração é praticamente a mesma, mas o título da janela não é necessário nesta versão; portanto, o comando para executá-la é:
python3 /path/to/startup_minimizd.py <command_to_run_application>
Assim como o primeiro script, ele precisa de ambos wmctrl
exdotool
#!/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)
Embora, em geral, a segunda versão deva ser mais confiável, nos casos em que o aplicativo é iniciado por um script de wrapper, o pid do comando será diferente do aplicativo finalmente chamado.
Nesses casos, eu recomendo usar o primeiro script.
Conforme solicitado em um comentário, abaixo de uma versão, feita especificamente para iniciar o STEAM minimizado.
Acontece que se Steam
comporta bem diferente de um aplicativo "normal":
Steam
que 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 tipo splash), mas às vezes uma janela de mensagem adicional aparece.pid 0
, o que é um problema no script como era.Esse comportamento excepcional de Steam
solicita uma versão especial do script, que é adicionada abaixo. O script é iniciado Steam
e, durante 12 segundos, fica de olho em todas as novas janelas correspondentes WM_CLASS
, verificando se elas são minimizadas. Caso contrário, o script garante que eles serão.
Como o script original, este precisa wmctrl
e xdotool
deve ser instalado.
#!/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)
runsteam_minimized.py
Execute-o pelo comando:
python3 /path/to/runsteam_minimized.py
except:
apenas para retornar Nenhum. Provavelmente é melhor deixá-lo falhar para que você veja o que falhou; caso contrário, poderá ocorrer por qualquer tipo de causa diferente e passar sem ser anunciado.
subprocess.CalledProcesError
(como resultado de um buggy wmctrl
) e IndexError
(exceção normal) serão editadas em um minuto :). Obrigado por mencionar
É bom ter os scripts fornecidos por user72216 e Sergey como soluções gerais para o problema, mas às vezes o aplicativo que você deseja inicializar minimizado já possui uma opção que fará o que você deseja.
Aqui estão alguns exemplos com as cadeias de comando correspondentes do programa de inicialização:
-startintray
opção:<path-to-Telegram>/Telegram -startintray
-silent
opção:/usr/bin/steam %U -silent
--minimized
opção:/usr/bin/transmission-gtk --minimized
No Unity, esses aplicativos são minimizados como ícones na barra de menus superior, e não como ícones no iniciador, 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.
Peguei os roteiros de Jacob e os modifiquei um pouco para criar um mais universal.
#!/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:
WAIT_TIME deve ser definido como grande o suficiente para permitir que o programa bifurque seus processos filhos. No meu computador, é suficiente para grandes programas como o steam. Aumente, se necessário.
Adição
xdotool
A opção de windowunmap
pode funcionar com alguns aplicativos e programas de bandeja (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)
startminimized
. Então eu corri startminimized gnome-calendar
. O calendário abre e continua funcionando?
WAIT_TIME
. Eu uso um atraso de 40 segundos para computadores fracos. Além disso, você pode tentar o segundo script, pois ele usa um comando diferente para minimizar o aplicativo.
Se o programa estiver sendo fechado na bandeja, é possível fechar a janela do programa na inicialização, em vez de minimizá-la. Um exemplo desse programa é o Viber. Nesse 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>
xdotool
não funcionará corretamente em instalações com Wayland.
Eu estava apenas navegando e me deparei com essa pergunta, então estava me perguntando qual é o seu sistema operacional? Quanto a mim, estou usando o UBUNTU BUDGIE 18.04 LTS, portanto, neste sistema operacional, é muito simples.
Basta ir ao menu
No menu, vá para Configurações da área de trabalho do Budgie
e
Em Configurações da área de trabalho, vá para Início automático
Isso lhe dará duas opções, de "+" add
1. Adicionar aplicativo
2. Adicionar comando
Ao selecionar Adicionar aplicativo, todos os aplicativos serão listados, selecione qualquer aplicativo desejado e ele será iniciado quando você iniciar o computador e também será minimizado.
Eu precisava dos programas fechados na bandeja, não minimizados, e tentei todos os scripts postados aqui, os que funcionavam, funcionavam apenas para alguns programas e não para outros. Então, eu codifiquei um que funciona muito melhor (você quase não vê a janela aparecendo, apenas o ícone da bandeja, ela parece nativa) e funciona para todos os programas que experimentei. É baseado no de Jacob. Com esse script, você pode precisar adicionar um argumento, dependendo do programa (veja abaixo), mas sempre trabalhou para mim em muitos programas, mas também deve funcionar com o steam.
Uso:
sudo apt-get install wmctrl xdotool
startup_closed.py
conceda permissões de execução e executepython3 ./startup_closed.py -c <command to open program>
-splash
ou -hide
, por tentativa e erro. Por exemplo: python3 ./startup_closed.py -hide -c teamviewer
oupython3 ./startup_closed.py -splash -c slack
./startup_closed.py --help
Roteiro:
#!/usr/bin/env python3
import subprocess
import sys
import time
import argparse
import random
parser = argparse.ArgumentParser(description='This script executes a command you specify and closes or hides the window/s that opens from it, leaving only the tray icon. Useful to "open closed to tray" a program. If the program does not have a tray icon then it just gets closed. There is no magic solution to achieve this that works for all the programs, so you may need to tweek a couple of arguments to make it work for your program, a couple of trial and error may be required with the arguments -splash and -hide, you probably will not need the others.')
parser.add_argument("-c", type=str, help="The command to open your program. This parameter is required.", required=True)
parser.add_argument("-splash", help="Does not close the first screen detected. Closes the second window detected. Use in programs that opens an independent splash screen. Otherwise the splash screen gets closed and the program cannot start.", action='store_true', default=False)
parser.add_argument("-hide", help="Hides instead of closing, for you is the same but some programs needs this for the tray icon to appear.", action='store_true', default=False)
parser.add_argument("-skip", type=int, default=0, help='Skips the ammount of windows specified. For example if you set -skip 2 then the first 2 windows that appear from the program will not be affected, use it in programs that opens multiple screens and not all must be closed. The -splash argument just increments by 1 this argument.', required=False)
parser.add_argument("-repeat", type=int, default=1, help='The amount of times the window will be closed or hidden. Default = 1. Use it for programs that opens multiple windows to be closed or hidden.', required=False)
parser.add_argument("-delay", type=float, default=10, help="Delay in seconds to wait before running the application, useful at boot to not choke the computer. Default = 10", required=False)
parser.add_argument("-speed", type=float, default=0.02, help="Delay in seconds to wait between closing attempts, multiple frequent attempts are required because the application may be still loading Default = 0.02", required=False)
args = parser.parse_args()
if args.delay > 0:
finalWaitTime = random.randint(args.delay, args.delay * 2);
print(str(args.delay) + " seconds of delay configured, will wait for: " + str(finalWaitTime))
time.sleep(finalWaitTime)
print("waiting finished, running the application command...")
command_check = args.c.split("/")[-1]
subprocess.Popen(["/bin/bash", "-c", args.c])
hasIndependentSplashScreen = args.splash
onlyHide = args.hide
skip = args.skip
repeatAmmount = args.repeat
speed = args.speed
actionsPerformed = 0
lastWindowId = 0
if hasIndependentSplashScreen:
skip += 1
while True:
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], [])
if len(match) > 0:
windowId = match[0]
if windowId != lastWindowId:
if skip > 0:
skip -= 1
print("skipped window: " + windowId)
lastWindowId = windowId
else:
print("new window detected: " + windowId)
if onlyHide:
subprocess.Popen(["xdotool", "windowunmap", windowId])
print("window was hidden: " + windowId)
else:
subprocess.Popen(["xdotool", "key", windowId, "alt+F4"])
print("window was closed: " + windowId)
actionsPerformed += 1
lastWindowId = windowId
if actionsPerformed == repeatAmmount:
break
except (IndexError, subprocess.CalledProcessError):
break
time.sleep(speed)
print("finished")
Eu vim com uma solução bastante elegante, que depende exclusivamente xdotool
, e é bastante útil para aplicativos que não possuem um argumento "iniciar minimizado" , como o Telegram.
A única desvantagem é que a solução precisa ser criada manualmente para cada aplicativo, mas supondo que isso não seja um problema (por exemplo: se você deseja iniciar automaticamente um determinado aplicativo sem permitir que ele polua sua tela após o login) , isso é muito mais simples e direto. .
## Starts Telegram and immediately closes it
xdotool search --sync --onlyvisible --name '^Telegram$' windowclose &
telegram-desktop &
## Starts WhatsApp and immediately closes it
xdotool search --sync --onlyvisible --name '(\([0-9]*\) ){0,1}(WhatsApp$|WhatsApp Web$)' windowclose &
whatsapp-nativefier &
À primeira vista, você pode pensar que é melhor usar o PID ou a classe do processo para comparar, no entanto, isso é realmente contraproducente, pois você frequentemente obtém vários resultados para o mesmo PID. Exemplos são uma janela 0x0 que está aguardando uma notificação, um ícone de bandeja ou qualquer outra janela "oculta".
A solução é criar um comando xdotool que sempre retorna apenas uma janela exclusiva . Nos dois exemplos que fiz --name
, no entanto, você pode combinar vários seletores com --all
(por exemplo: corresponder a um determinado nome de classe + um nome de classe + um nome regex) . Normalmente, um bom --name
regex faz o truque.
Após criar suas search
condições, basta gerar uma instância do xdotool (desanexada do shell) com o --sync
parâmetro e suas condições, seguidos por windowclose
. Execute seu aplicativo depois:
xdotool search --sync [... myapp-match-conditions] windowclose &
my-app
Confira
xdotool search --help
todas as possibilidades de combinações que você pode organizar para poder segmentar exatamente a janela desejada. Às vezes, fica complicado e você precisa combinar várias condições, mas, uma vez terminado, raramente falha (a menos que uma atualização altere o aplicativo e interrompa sua implementação, é claro).