【问题标题】:How to move or resize X11 windows (even if they are maximized)?如何移动或调整 X11 窗口的大小(即使它们已最大化)?
【发布时间】:2014-07-14 01:39:13
【问题描述】:

我想改变一个窗口的位置。我的问题是窗口可以最大化,这不允许改变它的大小和位置(窗口可以属于任何应用程序)。我使用 KDE4。


我尝试使用ewmh Python 模块。在我的情况下,当窗口最大化时,我只想将它从一个监视器移动到另一个监视器,使其保持最大化。我需要将其取消最大化以设置其几何形状,因此我尝试使用ewmh.setWmState() 将其取消最大化,将_NET_WM_STATE_MAXIMIZED_VERT_NET_WM_STATE_MAXIMIZED_HORZ 设置为0,然后ewmh.display.flush()

有时我可以配置以前最大化的窗口的位置和大小,有时不能。由于某种原因,它不能可靠地工作,如果我刚刚使用xrandr 从单显示器切换到三显示器,最大化窗口尤其可能会失败。

请注意,取消最大化总是有效的,(通常)不起作用的是之后更改窗口位置(或大小)。


我也尝试在终端中执行此操作。这是重现我的问题的最简单方法。首先,获取某个最大化窗口的窗口 ID ($WID)。那么:

wmctrl -i -r $WID -b remove,maximized_vert,maximized_horz
wmctrl -i -r $WID -e 0,1280,50,1250,1250

但第二个命令什么都不做,除非我在运行它之前手动移动或调整窗口大小。与ewmh 不同,如果窗口最大化,wmctrl 永远不会按预期工作。 wmctrl 成功取消最大化窗口,但之后无法更改其位置或大小。

这在单显示器和三显示器 X 屏幕状态下都可以重现。

此问题似乎并非特定于任何特定工具。例如,如果窗口刚刚未最大化但未手动移动/调整大小,xdotool 也无法更改窗口大小/位置。


到目前为止,我发现的唯一可靠的解决方法是手动取消窗口最大化,使用ewmhwmctrl,然后手动更改窗口大小或手动移动一点。只有这样我才能使用ewmhwmctrl 移动或调整它的大小。但显然这不是可接受的解决方案。

即使窗口当前已最大化,是否有可靠的方法来设置窗口几何图形?首选通过 Python 的方法,但使用 shell 命令的解决方案也可以。

【问题讨论】:

  • 您正在使用的“emwh”python 模块看起来有点“隐藏”(不能使用“pip”从 pypi 安装)-告诉你从哪里得到它可能会提高你获得正确的机会回答。我在“xpybutil”项目中找到了一个具有此名称的模块,如果不对我的系统进行一些调整,它就无法构建。
  • 我在我的问题中添加了指向 ewmh 模块的链接。它有时会按预期工作,因此 wmctrl 更适合重现问题:如果您管理 wmctrl -e ... 工作(通过在它之前运行一些 shell 命令或 python 代码),那么 ewmh 的问题也将得到解决。所以这个问题不是关于特定模块,而是关于找到可靠的方法来设置最大化窗口的几何形状。明显的方法是首先取消最大化窗口,但由于某种原因,未最大化的窗口往往会忽略设置其几何图形的尝试(就像它们仍然被最大化一样),除非我先手动移动/调整它们。
  • 由于某种奇怪的原因,一个新近未最大化的窗口无法以编程方式移动或调整大小。这种行为在工具和窗口管理器中是一致的。取消映射然后在取消最大化后立即将窗口映射回来似乎有帮助。我不知道为什么。

标签: python linux shell window x11


【解决方案1】:

感谢 n.m.评论我找到了解决方案。以下是我的 python script 中的相关部分(它保存和恢复所有窗口的状态和几何形状,因此本示例取消最大化、取消映射和映射所有窗口):

from time import sleep
from ewmh import EWMH
from Xlib import display, protocol, X
from Xlib.protocol.request import *
...
ewmh = EWMH()
disp = display.Display()
poll_interval = 0.025 # s
poll_attempts_limit = 10
...
def unmaximize(window):
  ewmh.setWmState(window, 0, "_NET_WM_STATE_MAXIMIZED_VERT")
  ewmh.setWmState(window, 0, "_NET_WM_STATE_MAXIMIZED_HORZ")
...
  for client in all_win:
    unmaximize(client.window)
  ewmh.display.flush()
  for client in all_win:
    client.xwin.unmap() 
  poll_attempts = 0
  for client in all_win:
    while client.xwin.get_attributes().map_state == X.IsViewable \
      and poll_attempts < poll_attempts_limit:
      sleep(poll_interval)
      poll_attempts += 1
  for client in all_win:
    client.xwin.map()   
  poll_attempts = 0
  for client in all_win:
    while client.xwin.get_attributes().map_state != X.IsViewable \
      and poll_attempts < poll_attempts_limit:
      sleep(poll_interval)
      poll_attempts += 1

执行此代码后,可以为任何窗口设置窗口几何形状。 all_win 是所有窗口的列表,表示为自定义类对象的列表,其中填充了来自 ewmh.getClientList() 的数据。每个client.xwin = disp.create_resource_object("window", client.id)。等待映射/取消映射完成很重要,否则将不可靠。此外,有必要限制轮询尝试以防止出现无限循环,以防某些窗口被意外映射或取消映射。


如果您不想一次重新配置很多窗口,使用 python xlib 模块进行取消映射和映射并没有明显的性能提升,使用 xdotool 会更容易:

from os import system
...
system("xdotool windowunmap --sync " + str(client.window.id))
system("xdotool windowmap   --sync " + str(client.window.id))

如果您想在 shell 脚本中设置窗口几何图形,即使窗口最大化,以下示例也应该可以工作:

wmctrl -i -r $WID -b remove,maximized_vert,maximized_horz
xdotool windowunmap --sync $WID
xdotool windowmap   --sync $WID
wmctrl -i -r $WID -e 0,$x,$y,$width,$height

【讨论】:

    猜你喜欢
    • 2011-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多