我只想运行 Telegram,我已将其添加到启动应用中。关键是我需要将其最小化。有什么命令吗?
答案1
启动最小化应用程序
以最小化方式启动应用程序需要两个命令:
- 启动应用程序
- 最小化窗口
因此,命令或脚本需要“智能”;第二个命令应该等待应用程序窗口实际出现。
启动应用程序最小化的通用解决方案
下面的脚本可以实现这一点,并且可以用作以最小化方式启动应用程序的通用解决方案。只需按照以下语法运行它:
<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 识别窗口
如果窗口标题不确定或可变,或者窗口名称存在名称冲突的风险,则使用pid
是更可靠的方法。
下面的脚本基于应用程序的 pid 的使用,如和 的输出wmctrl -lp
所示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 将与最终调用的应用程序不同。
在这种情况下,我建议使用第一个脚本。
EDIT2 Steam 脚本的特定版本
根据评论中的要求,以下是专为启动 STEAM 最小化而制作的版本。
为什么要为 Steam 设置特定版本?
事实证明,Steam
它的行为与“正常”应用程序完全不同:
- 事实证明
Steam
并不运行一pid,但不小于(在我的测试中)八! Steam
启动时运行至少两个窗口(一个类似启动画面的窗口),但有时会出现一个附加消息窗口。- Steam 的 Windows 版本有
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
答案2
最好将 user72216 和 Sergey 提供的脚本作为问题的一般解决方案,但有时您希望最小化启动的应用程序已经有一个可以执行您想要的操作的开关。
以下是一些带有相应启动程序命令字符串的示例:
- Telegram(自 0.7.10 版本起)有以下
-startintray
选项:<path-to-Telegram>/Telegram -startintray
- Steam 有以下
-silent
选项:/usr/bin/steam %U -silent
- 传动装置有以下
--minimized
选项:/usr/bin/transmission-gtk --minimized
在 Unity 中,这些应用程序启动时会最小化为顶部菜单栏中的图标,而不是启动器上的图标,不过一旦您开始使用该应用程序,正常的启动图标仍会出现。其他应用程序的行为可能有所不同。
答案3
我需要将程序关闭到托盘,而不是最小化,我尝试了这里发布的所有脚本,那些有效的脚本只对某些程序有效,对其他程序无效。所以我编写了一个效果更好的脚本(您几乎看不到窗口出现,只有托盘图标,它看起来像原生的),并且适用于我尝试过的所有程序。它基于 Jacob 的脚本。使用此脚本,您可能需要根据程序添加参数(见下文),但它总是对我的许多程序有效,它也应该适用于 steam。
用法:
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")
答案4
我想到了一个相当优雅的解决方案,它完全依赖于xdotool
,对于没有的应用程序来说,它非常有用“最小化启动”论点,就像 Telegram 一样。
唯一的缺点是必须为每个应用程序手动制定解决方案,但假设这不是问题(例如:如果您想在登录后自动启动某个应用程序而不允许其污染您的屏幕),这就简单直接多了。
实例
## 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
所有可以安排的组合可能性,以便能够精确定位您想要的窗口。有时它会变得很棘手,您必须组合多个条件,但一旦完成,它几乎不会失败(当然,除非更新更改了应用程序并破坏了您的实现)。