如何使用 Python 获取任务栏大小和位置

如何使用 Python 获取任务栏大小和位置

我正在用 Python 开发一个模块,我想找到一种方法来获得显示器分辨率减去任务栏,而无需任何用户交互,最好是以不干扰视觉界面的方式。如果我能获得任务栏的大小和位置,我可以轻松地从显示器分辨率中减去它。然而,我似乎找不到办法。

在 Windows 中,我可以使用模块win32api并使用GetMonitorInfo它获取显示器分辨率。但是,我还没有找到在 Ubuntu 或 Linux 中执行此操作的方法。如果您也有在 macOS 中执行此操作的方法,那也很好,但对于这个问题来说不是必需的。

我希望支持尽可能多的桌面环境,但我意识到这样做会非常困难,因为每个桌面环境可能都有自己的解决方案。考虑到这一点,我更愿意从以下桌面环境开始:

  • 桌面环境
  • 西门子
  • 侏儒
  • 肉桂

如果这需要一些外部程序来实现,我宁愿使用桌面环境或操作系统自带的东西。

答案1

我想找到一种方法来获得显示器分辨率减去任务栏,而无需任何用户交互,最好是以不干扰视觉界面的方式。

这就是被问到的问题,我将根据我的发现,在整个回答中重点关注这个问题。获取任务栏大小和位置是一个原创想法,但正如评论中所讨论的那样,如果不了解大量信息,这将很难实现 - 哪个面板或停靠栏正在运行,它们是否设置了 _NET_WM_STRUT属性,它们是否通过 GSettings 数据库或其他方法公开该信息。我确信这并非不可能,但相当困难。

NET_WORKAREA 属性

根据规格对于根窗口,_NET_WORKAREA 定义如下:

_NET_WORKAREA,x,y,宽度,高度 CARDINAL/32

此属性必须由窗口管理器在计算每个桌面的工作区时设置。包含每个桌面的几何图形。这些几何图形是相对于每个桌面上的视口指定的,并指定完全包含在视口内的区域。桌面应用程序应使用工作区来适当地放置桌面图标。

窗口管理器应该通过将当前页面减去停靠窗口和面板窗口占用的空间来计算该空间,如客户端窗口上设置的 _NET_WM_STRUT 或 _NET_WM_STRUT_PARTIAL 属性所示。

有几点需要注意:

  • 符合这些规范的窗口管理器必须设置此属性,因此在 XFCE、Budgie、Unity、GNOME、KDE ​​等桌面环境中 - 即任何不使用任何实验性窗口管理器的官方 Ubuntu 版本都将设置此属性;换句话说,这将在受支持的桌面上运行
  • 这将计算可用的宽度和高度,以及相对于整个显示屏最左角的偏移开始位置(在双屏的情况下,最左边屏幕的左上角将是起点)
  • _NET_WM_STRUT_NET_WM_STRUT_PARTIAL是 docks 和 panel 设置的属性。这意味着,如果 panel 或 dock 没有设置它,它们基本上会表现得像一个普通窗口,只是位于所有其他窗口之上(并且可能会让用户感到烦恼1 。也就是说,这对我们来说已经足够好了。我已经在 Ubuntu 18.04 上的 Cinnamon、LXQt 和 XFCE 上测试了这个属性。在所有情况下,docks 和 panel 都会正确地通知窗口管理器它们的支柱区域。这意味着,_NET_WORKAREA在 99% 的情况下都会为你工作。

xprop可以通过根窗口上的实用程序在 shell 中查询此属性。

$ xprop -root _NET_WORKAREA
_NET_WORKAREA(CARDINAL) = 0, 32, 3120, 974, 0, 32, 3120, 974

这是我使用双显示器设置的输出,两个显示器沿顶部对齐,一个底座和一个顶部面板。如果您注意到只有前四个值是重要的,其他四个值是重复的。特别有趣的是3120974。这是我们感兴趣的值。前两个告诉我们在哪里桌面最左角开始。我的顶部面板占用 32 点,因此桌面最左角从左侧开始,向下偏移 32 点。对于窗口来说,底部偏移通常无关紧要 - 它们将填充可用的工作区。

如果我将 Dock 放在主显示器的右侧,您会注意到宽度减小了,但高度却减小了:

$ xprop -root _NET_WORKAREA
_NET_WORKAREA(CARDINAL) = 0, 32, 3059, 1018, 0, 32, 3059, 1018

高度变化为 44 点。在此基础上再添加 32(顶部面板窗口的大小),您将获得 1050,与我的桌面的几何形状完全相同(请注意,之前没有停靠点时的尺寸为 3120,因此使用了整个桌面宽度):

$ xprop -root _NET_DESKTOP_GEOMETRY
_NET_DESKTOP_GEOMETRY(CARDINAL) = 3120, 1050

Python 和xprop

上面的命令xprop在大多数桌面上都有,并且属于x11 实用程序软件包,因此如果你的目标是基于 Debian 的主要系统,那么大多数时候你都应该可以使用它。我会使用 Python 的子进程,并利用subprocess.check_output()subprocess.run()命令通过模块解析输出re

>>> import re,subprocess
>>> out = subprocess.check_output(['xprop','-root','_NET_WORKAREA'])
>>> workarea_tokens = re.split('=|,',out.decode())
>>> workarea_tokens[1:5]
[' 0', ' 32', ' 3059', ' 1018']

Python 和 Gdk

另一种方法(通常是我首选的方法)是利用与以下方法密切相关的 Gdk 库其他 GNOME 项目库。如果您使用 Gtk 开发桌面应用程序,那么您已经拥有了必要的工具,那么为什么不使用它们呢?棘手的部分是您必须为每个单独的显示器计算工作区。

#!/usr/bin/env python3
import gi
gi.require_version('Gtk','3.0')
gi.require_version('Gdk','3.0')
from gi.repository import Gdk,Gtk,GdkX11

display = Gdk.Display().get_default()
for i in range(display.get_n_monitors()):
    monitor = display.get_monitor(i)
    w_area  = monitor.get_workarea()
    print(w_area.x, w_area.y,
          w_area.width, w_area.height)

该程序的运行结果:

$ python3  display_area.py
1440 32 1619 1018
0 0 1440 900
# width of two monitors with dock on right adds up to _NET_WORKAREA
$ echo $((1619+1440))
3059
$ xprop -root _NET_WORKAREA
_NET_WORKAREA(CARDINAL) = 0, 32, 3059, 1018, 0, 32, 3059, 1018

问题

现在,还记得我提到过我有双显示器吗?这样的设置开启了很多可能性,但也暴露了某些奇怪的行为。

# added xfce4-panel at the bottom of second screen, no change in height - 900
$ python3 display_area.py ; xprop -root _NET_WORKAREA
1440 32 1619 1018
0 0 1440 900
_NET_WORKAREA(CARDINAL) = 526, 32, 2533, 1018, 526, 32, 2533, 1018
# stopped xfce4-panel process, same height - 900
$ python3 display_area.py ; xprop -root _NET_WORKAREA
1440 32 1619 1018
0 0 1440 900
_NET_WORKAREA(CARDINAL) = 0, 32, 3059, 1018, 0, 32, 3059, 1018
# added xfce4-panel to the top of second monitor
$ python3 display_area.py ; xprop -root _NET_WORKAREA
1440 49 1619 1001
0 0 1440 900
_NET_WORKAREA(CARDINAL) = 0, 49, 3059, 1001, 0, 49, 3059, 1001

xfce4-panel请记住,我在一个屏幕上有一个面板和一个底座,并在另一个屏幕上添加了测试。Gdk 的错误结果是第二台显示器的工作区没有改变。xprop还报告了错误的数字 - 在第一个输出中526,左侧偏移点根本不正确。然而,在最后一个输出中,垂直偏移增加了,这是好事 - 增加的额外宽度xfce4-panel应该添加到总数中,可能有帮助的是我的两个显示器在顶部对齐。

换句话说,如果您的应用程序计划确定没有停靠栏和面板的区域,这些方法最适合单显示器设置。在双显示器设置中 - 结果可能会不一致。请注意,我使用的是 Metacity 窗口管理器,错误可能归因于此。但是,我目前没有办法测试其他具有双显示器设置的窗口管理器,因此我将本节保留为不确定的。

TODO(某天)

  • C 或 Python 中的 libx11 示例

  • 使用替代窗口管理器进行双显示器测试

  • 查找停靠栏和面板位置


脚注

1未记录的功能,取决于用户的耐心程度。

相关内容