Je veux juste que Telegram soit lancé et je l'ai ajouté aux applications de démarrage. Le problème est que j'ai besoin qu'il soit minimisé. Quelles sont les commandes ?
Réponses
Trop de publicités?Il est bon d'avoir les scripts donnés par user72216 et Sergey comme solutions générales au problème, mais parfois l'application que vous souhaitez démarrer minimisée a déjà un commutateur qui fera ce que vous voulez.
Voici quelques exemples avec les chaînes de commande correspondantes du programme de démarrage :
- Telegram (depuis la version 0.7.10) dispose de la fonction
-startintray
option :<path-to-Telegram>/Telegram -startintray
- Steam a la
-silent
option :/usr/bin/steam %U -silent
- La transmission a la
--minimized
option :/usr/bin/transmission-gtk --minimized
Dans Unity, ces applications sont réduites sous forme d'icônes dans la barre de menu supérieure plutôt que sous forme d'icônes dans le lanceur, bien que l'icône de lancement normale apparaisse toujours une fois que vous commencez à utiliser l'application. D'autres applications peuvent se comporter différemment.
J'avais besoin que les programmes soient fermés dans la barre des tâches, et non minimisés, et j'ai essayé tous les scripts postés ici, ceux qui fonctionnaient, ne fonctionnaient que pour certains programmes et pas pour d'autres. J'en ai donc codé un qui fonctionne beaucoup mieux (on ne voit presque pas la fenêtre apparaître, seulement l'icône de la barre des tâches, cela semble natif) et qui fonctionne pour tous les programmes que j'ai essayés. Il est basé sur celui de Jacob. Avec ce scripts vous pouvez avoir besoin d'ajouter un argument en fonction du programme (voir ci-dessous) mais il a toujours fonctionné pour moi avec beaucoup de programmes, il devrait également fonctionner avec steam.
Uso:
sudo apt-get install wmctrl xdotool
- Enregistrez le script en tant que
startup_closed.py
donnez-lui des droits d'exécution, puis exécutezpython3 ./startup_closed.py -c <command to open program>
- Si l'icône de la barre des tâches ne s'affiche pas ou si la fenêtre ne s'affiche pas, vous devez ajouter l'un de ces arguments :
-splash
o-hide
par essais et erreurs. Par exemple :python3 ./startup_closed.py -hide -c teamviewer
opython3 ./startup_closed.py -splash -c slack
- Il existe d'autres arguments, mais vous n'en avez probablement pas besoin. De plus, l'aide explique en détail quand et pourquoi les arguments sont nécessaires :
./startup_closed.py --help
script :
#!/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")
J'ai pris les scripts de Jacob et les ai modifiés un peu pour en faire un plus universel.
#!/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)
Les principales différences sont les suivantes :
- Le programme définit l'ID de groupe (GID) pour le processus. Ainsi, tous les processus enfants et leurs Windows peuvent être facilement trouvés
- L'option xdotool --sync est utilisée à la place d'une boucle while
- script permet de passer des arguments au programme
WAIT_TIME doit être suffisamment important pour permettre au programme de forker ses processus enfants. Sur mon ordinateur, c'est suffisant pour les gros programmes comme steam. Augmentez-le si nécessaire.
Ajout
xdotool
L'option du windowunmap
peut fonctionner bizarrement avec certaines applications et certains programmes de plateau (le plateau de linux mint, par exemple), voici donc une version alternative du script pour ces exceptions.
#!/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)
Si le programme est fermé dans la zone de notification, on peut vouloir fermer la fenêtre du programme au démarrage au lieu de la réduire. Viber est un exemple de ce type de programme. Dans ce cas, on peut utiliser le script suivant 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>
J'ai trouvé une solution assez élégante qui s'appuie exclusivement sur xdotool
et c'est très utile pour les applications qui n'ont pas d'interface utilisateur. "démarrage minimisé" comme Telegram.
Le seul inconvénient est que la solution doit être élaborée manuellement pour chaque application, mais cela ne devrait pas poser de problème. (par exemple, si vous voulez démarrer automatiquement une certaine application sans qu'elle pollue votre écran après la connexion) Il s'agit d'une méthode beaucoup plus simple et directe.
Exemples concrets
## 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 &
La solution
À première vue, on pourrait penser qu'il est préférable d'utiliser le PID ou la classe du processus pour établir la correspondance, mais c'est en fait contre-productif, car vous obtiendrez souvent plusieurs résultats pour le même PID. Par exemple, une fenêtre 0x0 qui attend en fait une notification, une icône de la barre d'état système ou toute autre fenêtre "cachée".
La solution est création d'une commande xdotool qui ne renvoie toujours qu'une seule fenêtre unique . Dans mes deux exemples, cela a été fait en utilisant --name
Toutefois, vous pouvez combiner plusieurs sélecteurs à l'aide de --all
(par exemple : correspondre à un nom de classe donné + un nom de classe + une expression rationnelle de nom) . En général, une bonne --name
fait l'affaire.
Après avoir élaboré votre search
il suffit de créer une instance de xdotool (détaché du Shell) avec le --sync
et vos conditions, suivi de windowclose
. Exécutez ensuite votre application :
xdotool search --sync [... myapp-match-conditions] windowclose &
my-app
Vérifier
xdotool search --help
pour toutes les possibilités de combinaisons que vous pouvez mettre en place pour cibler exactement la fenêtre que vous souhaitez. Parfois, cela devient délicat et vous devez combiner plusieurs conditions, mais une fois que vous avez terminé, il est rare que cela échoue (à moins qu'une mise à jour ne modifie l'application et ne brise votre implémentation, bien sûr).
- Réponses précédentes
- Plus de réponses