如何在启动时运行程序,最小化?

我只想运行Telegram并将其添加到启动应用程序中。 关键是我需要将它最小化。 任何命令?

最小化启动应用程序

以最小化的方式启动应用程序需要两个命令:

  • 启动应用程序
  • 最小化它的窗口

因此,命令或脚本需要“智能”; 第二个命令应该等待应用程序窗口实际出现。

最小化启动应用程序的一般解决方案

下面的脚本可以做到这一点,并且可以用作以最小化方式启动应用程序的通用解决方案。 只需在语法中运行它:

 

剧本

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

如何使用

该脚本需要wmctrlxdotool

 sudo apt-get install wmctrl xdotool 

然后:

  1. 将脚本复制到空文件中,将其另存为startup_minimizd.py
  2. 测试 - 运行脚本(例如) gedit命令:

     python3 /path/to/startup_minimizd.py gedit gedit 
  3. 如果一切正常,请将命令(适用于您的应用程序)添加到Startup Applications

说明

  • 该脚本启动应用程序,运行您作为第一个参数提供的命令
  • 然后脚本检查窗口列表(在wmctrl的帮助下),以第二个参数命名的窗口。
  • 如果窗口出现,则会在xdotool的帮助下立即最小化。如果由于某种原因窗口可能不显示,则防止出现无限循环,脚本会出现30秒的时间限制以显示窗口。

注意

无需提及您可以一次将脚本用于多个应用程序,因为您使用脚本外部的参数运行它。


编辑

通过它的pid识别窗口

如果窗口标题不确定或可变,或者窗口名称中存在名称冲突的风险,则使用pid是一种更可靠的方法。

下面的脚本基于应用程序的pid的使用,如wmctrl -lpps -ef的输出。

设置几乎相同,但此版本不需要窗口标题,因此运行它的命令是:

 python3 /path/to/startup_minimizd.py  

就像第一个脚本一样,它需要wmctrlxdotool

剧本

 #!/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的特定版本?

事实certificate, Steam行为与“普通”应用程序完全不同:

  • 事实certificateSteam不会运行一个 pid,但不会少于(在我的测试中) 八个!
  • Steam启动时至少有两个窗口(一个类似于窗口的窗口),但有时会出现另一个消息窗口。
  • Steam的Windows有pid 0 ,这是脚本中的一个问题。
  • 创建主窗口后,窗口会在一秒左右后再次上升,因此单个最小化将不会。

Steam这种特殊行为要求提供特殊版本的脚本,该脚本将在下面添加。 脚本启动Steam ,在12秒内,它会关注相应WM_CLASS所有新窗口,检查它们是否被最小化。 如果没有,脚本确保它们将是。

像原始脚本一样,这个脚本需要安装wmctrlxdotool

剧本

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

将user72216和Sergey提供的脚本作为问题的一般解决方案是很好的,但有时您希望最小化启动的应用程序已经有一个可以执行您想要的操作的开关。

以下是相应的启动程序命令字符串的一些示例:

  • Telegram(自0.7.10版本起)具有-startintray选项: /Telegram -startintray
  • Steam有-silent选项: /usr/bin/steam %U -silent
  • 传输具有--minimized选项: /usr/bin/transmission-gtk --minimized

在Unity中,这些应用程序在顶部菜单栏中作为图标开始最小化,而不是作为启动器上的图标,尽管一旦开始使用该应用程序,仍会显示正常的启动图标。 其他应用程序可能表现不同。

我拿了Jacob的脚本并对它们进行了一些修改以使其更加通用。

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

主要区别是:

  • 程序设置进程的组ID(GID)。 因此,可以很容易地找到所有子进程及其窗口
  • 使用xdotool –sync选项而不是while循环
  • 脚本允许将参数传递给程序

应将WAIT_TIME设置得足够大,以允许程序分叉其子进程。 在我的电脑上,对于像steam这样的大型程序来说已经足够 如果需要,增加它。

加成

xdotool的选项windowunmap可能与某些应用程序和托盘程序(例如linux mint的托盘)一起使用时,所以这里是这些exception的脚本的替代版本。

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

如果程序被关闭到托盘,可能实际上想要在启动时关闭程序窗口而不是最小化它。 这种程序的一个例子是Viber。 在这种情况下,可以使用以下脚本start_closed.sh

 #!/bin/bash # Check that there is only one input argument if [[ $# -gt 1 ]]; then echo "Usage: $0 " 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 

用法: