我需要一个列表,其中仅包含当前在 Dash 中打开/运行的应用程序,即图标左侧带有小白色箭头的应用程序。
有什麼方法可以得到它?
答案1
有趣的问题。
与往常一样,有不同的方法可以获得这些应用程序的列表,每种方法都有特定的优点和缺点。
使用窗口列表获取启动器中显示的进程列表
由于只有具有(映射)窗口的应用程序才会出现在启动器中,因此使用:
wmctrl -lp
(wmctrl
默认情况下未安装),我们可以获取已打开窗口的列表以及窗口所属的进程 ID。输出的格式为:
0x05204641 0 12618 jacob-System-Product-Name verhaal (~) - gedit
对我们来说最重要的信息是:
- 第一个字符串(
0x05204641
);这是窗口 ID - 第三个字符串(
12618
);这是进程 ID(pid)该窗口所属的,以及 - 最后一部分(
verhaal (~) - gedit
);这是窗口姓名。
一旦我们有了 pid,我们就可以查找相应的进程姓名通过以下命令:
ps -p <pid> -o comm=
我们可以编写上述步骤的脚本,并列出现有窗口的输出,如下所示(使用python
):
{'gnome-terminal', 'nautilus', 'gedit', 'GuitarPro.exe', 'firefox', 'thunderbird', 'soffice.bin'}
并发症
这看起来很简单。然而,现实总是有点复杂。我们需要注意一些例外和复杂情况:
- 有些窗口将属于进程 0,当尝试获取其属性时将引发错误。
Idle
(python
IDE)的窗口或tkinter
就是这样的窗口。 - 有些窗口不是“真实”窗口,例如临时窗口(从其他窗口调用并属于其他窗口的窗口)或例如桌面本身。这些窗口在 的输出中列为窗口
wmctrl
,但不会在 Dash 中单独出现。 LibreOffice
在某些情况下,应用程序的名称与进程名称有很大不同,例如在所有模块的进程名称为 的情况下soffice.bin
。同时,运行命令soffice.bin
无法正常工作。如果您需要识别模块(Calc
等Writer
),你需要从窗口的姓名例如。- 另一个示例是 的进程名称
gnome-terminal
,如 的输出所示,出现在 进程列表中ps -e ww
。在 14.04 中,gnome-terminal
显示为gnome-terminal
,然而,在 15.04 / 15.10 中它显示为:/usr/lib/gnome-terminal/gnome-terminal-server
。
我们需要解决的问题至少
要解决上述最重要的问题,您需要:
添加检查,以确认窗口是“真实”窗口还是“正常”窗口,使用以下方法检查
xprop -id <window_id>
如果输出包含以下行:
_NET_WM_WINDOW_TYPE(ATOM) = _NET_WM_WINDOW_TYPE_NORMAL
该窗口是 Unity Launcher 意义上的有效窗口
gnome-terminal
要修复中的进程名称15.x
(假设您希望显示的进程名称为gnome-terminal
),我们需要添加一个例外,gnome-terminal
当进程名称显示为时, 将其重命名为/usr/lib/gnome-terminal/gnome-terminal-server
脚本
#!/usr/bin/env python3
import subprocess
import sys
try:
listed = sys.argv[1]
except IndexError:
listed = []
get = lambda cmd: subprocess.check_output(cmd).decode("utf-8").strip()
def check_wtype(w_id):
# check the type of window; only list "NORMAL" windows
return "_NET_WM_WINDOW_TYPE_NORMAL" in get(["xprop", "-id", w_id])
def get_process(w_id):
# get the name of the process, owning the window
proc = get(["ps", "-p", w_id, "-o", "comm="])
proc = "gnome-terminal" if "gnome-terminal" in proc else proc
return proc
wlist = [l.split() for l in subprocess.check_output(["wmctrl", "-lp"])\
.decode("utf-8").splitlines()]
validprocs = set([get_process(w[2]) for w in wlist if check_wtype(w[0]) == True])
if listed == "-list":
for p in validprocs:
print(p)
else:
print(validprocs)
如何使用
该脚本需要
wmctrl
:sudo apt-get install wmctrl
将上述脚本复制到一个空文件中,保存为
get_running.py
通过命令运行它:
python3 /path/to/get_running.py
它将输出如下内容:
{'gnome-terminal', 'nautilus', 'gedit', 'GuitarPro.exe', 'firefox', 'thunderbird', 'soffice.bin'}
或者,使用以下参数运行
-list
:thunderbird nautilus gnome-terminal firefox gedit GuitarPro.exe soffice.bin
笔记
从您的问题来看,找到的列表的用途并不完全清楚。如果您需要应用程序的名称(如界面中显示的名称(“可读”名称),则可能适合采用完全不同的方法:
- 所有全局安装的应用程序在 中都有一个
.desktop
文件/usr/share/applications
。在大多数情况下,我们可以得出进程名称和应用程序文件中的界面名称.desktop
。利用此信息,我们可以相对轻松地创建正在运行的 GUI 应用程序列表,并以“可读”的名称呈现。
然而,在这种情况下,现实也比理论更复杂,正如所解释的那样这里。
答案2
qdbus
使用和界面来实现的方法org.ayatana.bamf
。
按文件列出的未结申请清单.desktop
:
$ qdbus org.ayatana.bamf /org/ayatana/bamf/matcher \
> org.ayatana.bamf.matcher.RunningApplicationsDesktopFiles
/usr/share/applications/compiz.desktop
/usr/share/applications/firefox.desktop
/usr/share/applications/x-terminal-emulator.desktop
使用org.ayatana.bamf.matcher.RunningApplications
和 org.ayatana.bamf.view.Name
方法
$ qdbus org.ayatana.bamf /org/ayatana/bamf/matcher \
> org.ayatana.bamf.matcher.RunningApplications | \
> xargs -I {} qdbus org.ayatana.bamf {} org.ayatana.bamf.view.Name
Firefox Web Browser
MY CUSTOM TERMINAL
Compiz