전보를 실행하고 시작 앱에 추가했습니다. 요점은 최소화해야한다는 것입니다. 어떤 명령?
전보를 실행하고 시작 앱에 추가했습니다. 요점은 최소화해야한다는 것입니다. 어떤 명령?
답변:
응용 프로그램을 최소화 된 방식으로 시작하려면 두 가지 명령이 필요합니다.
따라서 명령 또는 스크립트는 "스마트"해야합니다. 두 번째 명령은 응용 프로그램 창이 실제로 나타날 때까지 기다려야합니다.
아래 스크립트는이를 수행하며 응용 프로그램을 최소화 된 방식으로 시작하는 일반적인 솔루션으로 사용할 수 있습니다. 다음 구문으로 실행하십시오.
<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
스크립트는 모두 필요 wmctrl
하고를 xdotool
:
sudo apt-get install wmctrl xdotool
그때:
startup_minimizd.py
gedit
다음 명령을 사용 하여 스크립트를 테스트하십시오 .
python3 /path/to/startup_minimizd.py gedit gedit
Startup Applications
wmctrl
)을 사용하여 두 번째 인수의 이름을 딴 창을 확인합니다.xdotool
어떤 이유로 창이 표시되지 않는 경우 무한 루프를 방지하기 위해 스크립트는 창이 표시되는 시간을 30 초로 제한합니다.스크립트 외부에서 인수를 사용하여 스크립트를 실행하므로 한 번에 여러 응용 프로그램에 스크립트를 사용할 수 있습니다.
창 제목이 확실하지 않거나 가변적이거나 창 이름에 이름이 충돌 할 위험이있는 경우를 사용하는 pid
것이보다 안정적인 방법입니다.
아래 스크립트는 두 가지 출력 모두에서 wmctrl -lp
와 같이 응용 프로그램의 pid 사용을 기반으로합니다.ps -ef
.
설정은 거의 동일하지만이 버전에서는 창 제목이 필요하지 않으므로 실행 명령은 다음과 같습니다.
python3 /path/to/startup_minimizd.py <command_to_run_application>
그냥 첫 번째 스크립트처럼이 필요로 모두 wmctrl
와xdotool
#!/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)
일반적으로 두 번째 버전이보다 안정적이어야하지만 래퍼 스크립트로 응용 프로그램을 시작한 경우 명령의 pid는 최종적으로 호출 된 응용 프로그램과 다릅니다.
이러한 경우 첫 번째 스크립트를 사용하는 것이 좋습니다.
주석에서 요청한대로, 버전 아래에서, 특히 STEAM 시작을 위해 만들어진 최소화.
그것은 밝혀 Steam
"정상적인"응용 프로그램에서 매우 다른 동작합니다을 :
Steam
실행하지는 않지만 (내 테스트에서) 8 이상 은 아닙니다 !Steam
시작 시 두 개 이상의 창 (하나의 스플래시 모양 창)으로 시작되지만 때때로 추가 메시지 창이 나타납니다.pid 0
에는 스크립트의 문제입니다.이 예외적 인 동작은 Steam
아래에 추가 된 특수 버전의 스크립트 를 요청합니다. 스크립트가 시작되고 Steam
12 초 동안 해당의 모든 새 창을 계속 WM_CLASS
확인 하여 최소화되어 있는지 확인합니다. 그렇지 않다면, 스크립트는 그들이 될 것임을 확인합니다.
원래 스크립트처럼,이 필요 wmctrl
하고이 xdotool
설치된다.
#!/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
다음 명령으로 실행하십시오 :
python3 /path/to/runsteam_minimized.py
except:
None을 반환 하려고하지는 않습니다 . 실패한 것이 무엇인지 알 수 있도록 실패하는 것이 좋습니다. 그렇지 않으면 모든 종류의 다른 원인으로 인해 중단 될 수 있으며 광고되지 않은 상태로 전달됩니다.
subprocess.CalledProcesError
(버그의 결과로 wmctrl
) 및 IndexError
(일반 예외)는 1 분 안에 편집됩니다 :). 언급 해 주셔서 감사합니다
user72216 및 Sergey가 문제에 대한 일반적인 솔루션으로 제공하는 스크립트를 사용하는 것이 좋지만 때로는 시작하려는 응용 프로그램에 최소화하려는 스위치가 이미 있습니다.
다음은 해당하는 시작 프로그램 명령 문자열이 포함 된 몇 가지 예입니다.
-startintray
옵션 이 있습니다.<path-to-Telegram>/Telegram -startintray
-silent
옵션 이 있습니다 :/usr/bin/steam %U -silent
--minimized
옵션 이 있습니다 :/usr/bin/transmission-gtk --minimized
Unity에서는 이러한 응용 프로그램이 시작 프로그램의 아이콘이 아니라 상단 메뉴 표시 줄의 아이콘으로 최소화되기 시작하지만, 응용 프로그램 사용을 시작하면 일반 시작 아이콘이 계속 나타납니다. 다른 응용 프로그램은 다르게 작동 할 수 있습니다.
나는 야곱의 대본을 가지고 좀 더 보편적 인 대본을 만들기 위해 대본을 수정했습니다.
#!/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)
주요 차이점은 다음과 같습니다.
WAIT_TIME은 프로그램이 하위 프로세스를 분기 할 수 있도록 충분히 크게 설정해야합니다. 내 컴퓨터에서는 증기와 같은 큰 프로그램에 충분합니다. 필요한 경우 늘리십시오.
부가
xdotool
의 옵션 windowunmap
은 일부 응용 프로그램 및 트레이 프로그램 (예 : Linux mint의 트레이)에서 펑키 할 수 있으므로 다음은 예외에 대한 대체 스크립트 버전입니다.
#!/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
. 그런 다음 나는 달렸다 startminimized gnome-calendar
. 캘린더가 열려 있고 계속 실행됩니까?
WAIT_TIME
. 약한 컴퓨터에는 40 초 지연을 사용합니다. 또한 다른 명령을 사용하여 앱을 최소화하므로 두 번째 스크립트를 사용해 볼 수 있습니다.
프로그램이 트레이에 닫혀 있으면 시작시 프로그램 창을 최소화하지 않고 닫고 싶을 수 있습니다. 그러한 프로그램의 한 예는 Viber입니다. 이 경우 다음 스크립트를 사용할 수 있습니다 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
용법: <path-to-script> <program-to-start>
xdotool
Wayland 설치에서는 제대로 작동하지 않을 수 있습니다 .
나는 단지 서핑을 하고이 질문을 보았으므로 운영 체제가 무엇인지 궁금합니다. 나에 관해서는 UBUNTU BUDGIE 18.04 LTS를 사용하고 있기 때문에이 운영 체제에서는 매우 간단합니다.
단순히 메뉴로 이동
메뉴에서 Budgie Desktop 설정으로 이동
과
데스크탑 설정에서 자동 시작으로 이동
"+"에서 2 가지 옵션을 제공합니다.
1. 응용 프로그램 추가
2. 명령 추가
응용 프로그램 추가 를 선택 하면 모든 응용 프로그램이 나열되고 원하는 응용 프로그램을 선택하고 컴퓨터를 시작할 때 시작되며 최소화됩니다.
나는 프로그램을 최소화하고 트레이에 닫아 두어야했으며 여기에 게시 된 모든 스크립트 (작동 한 스크립트는 일부 프로그램에서만 작동하고 다른 스크립트에서는 작동하지 않음)를 시도했습니다. 그래서 나는 훨씬 더 잘 작동하는 것을 코딩했습니다 (창이 거의 보이지 않고 트레이 아이콘 만 표시되며 기본 모양으로 보입니다). 내가 시도한 모든 프로그램에서 작동합니다. 그것은 야곱의 것을 근거로합니다. 이 스크립트를 사용하면 프로그램에 따라 인수를 추가해야 할 수도 있지만 (아래 참조) 항상 많은 프로그램을 사용하여 증기를 처리해야합니다.
용법:
sudo apt-get install wmctrl xdotool
startup_closed.py
실행 권한을 부여한 다음 실행python3 ./startup_closed.py -c <command to open program>
-splash
또는 -hide
시행 착오. 예를 들어 : python3 ./startup_closed.py -hide -c teamviewer
또는python3 ./startup_closed.py -splash -c slack
./startup_closed.py --help
스크립트:
#!/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")
나는 독점적으로에 의존하는 다소 우아한 솔루션을 제공했으며 Telegram과 같이 "최소화 시작" 인수가 xdotool
없는 응용 프로그램에 매우 유용합니다 .
유일한 단점은 각 앱에 대해 솔루션을 수동으로 만들어야하지만 문제가 아니라고 가정하면 (예 : 로그인 한 후 화면을 오염시키지 않고 특정 응용 프로그램을 자동 시작하려는 경우) 훨씬 간단하고 간단합니다. .
## 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 &
언뜻 보면 프로세스의 PID 또는 클래스를 사용하여 일치시키는 것이 낫다고 생각할 수도 있지만 동일한 PID에 대해 여러 결과를 자주 얻을 수 있기 때문에 실제로는 비생산적입니다. 실제로는 알림, 시스템 트레이 아이콘 또는 기타 "숨겨진"창을 기다리는 0x0 창이 있습니다.
이 솔루션은 항상 하나의 고유 창만 반환하는 xdotool 명령을 작성하고 있습니다 . --name
그러나을 사용하여 수행 한 두 가지 예제 모두에서 여러 선택기를 결합 할 수 있습니다 --all
(예 : 주어진 클래스 이름 + 클래스 이름 + 이름 정규식 일치) . 일반적으로 좋은 --name
정규 표현식이 트릭을 수행합니다.
search
조건을 작성한 후 , 매개 변수와 조건과 함께 xdotool 인스턴스 (쉘에서 분리)를 스폰하면 --sync
됩니다 windowclose
. 나중에 앱을 실행하십시오.
xdotool search --sync [... myapp-match-conditions] windowclose &
my-app
xdotool search --help
원하는 정확한 창을 타겟팅 할 수있는 조합의 모든 가능성을 확인하십시오 . 때로는 까다로워지고 여러 가지 조건을 결합해야하지만 일단 업데이트가 완료되면 응용 프로그램이 변경되어 구현이 중단되지 않는 한 거의 실패하지 않습니다.