简体   繁体   English

如何移动或调整X11窗口的大小(即使它们最大化)?

[英]How to move or resize X11 windows (even if they are maximized)?

I want to change position of a window. 我想改变一个窗口的位置。 My problem is that the window can be maximized, this does not allow to change its size and location (window can belong to any application). 我的问题是窗口可以最大化,这不允许改变它的大小和位置(窗口可以属于任何应用程序)。 I use KDE4. 我用的是KDE4。


I tried to use ewmh Python module. 我试着使用ewmh Python模块。 In my case when the window is maximized I just want to move it from one monitor to the other, keeping it maximized. 在我的情况下,当窗口最大化时,我只想将它从一个监视器移动到另一个监视器,使其保持最大化。 I need to unmaximize it to set its geometry, so I tried to unmaximize it using ewmh.setWmState() to set _NET_WM_STATE_MAXIMIZED_VERT , _NET_WM_STATE_MAXIMIZED_HORZ to 0 , then ewmh.display.flush() . 我需要ewmh.setWmState()以设置其几何,所以我尝试使用ewmh.setWmState()将其ewmh.setWmState()以将_NET_WM_STATE_MAXIMIZED_VERT_NET_WM_STATE_MAXIMIZED_HORZ设置为0 ,然后设置为ewmh.display.flush()

Sometimes I can configure the position and size of a previously maximized window, sometimes not. 有时我可以配置以前最大化窗口的位置和大小,有时不配置。 For some reason it does not work reliably, and is especially likely to fail for maximized windows if I just switched from a single-monitor to triple monitors with xrandr . 由于某些原因,它不能可靠地工作,如果我只是从单显示器切换到带有xrandr三显示器,则特别有可能因最大化窗口而失败。

Please note that unmaximizing always works, what (often) does not work is changing window position (or size) afterwards. 请注意,取消最大化始终有效,(通常)不起作用的是之后改变窗口位置(或大小)。


I also tried doing this in the terminal. 我也试过在终端做这个。 This is the easiest way to reproduce my problem. 这是重现我的问题的最简单方法。 First, get the Window ID ( $WID ) for some maximized window. 首先,获取某个最大化窗口的窗口ID( $WID )。 Then: 然后:

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

But the second command does nothing unless I move or resize the window manually before running it. 但是第二个命令什么都不做,除非我在运行它之前手动移动或调整窗口大小。 Unlike ewmh , wmctrl never works as expected if the window is maximized. ewmh不同,如果窗口最大化, wmctrl无法按预期工作。 wmctrl unmaximizes the window successfully but cannot change its position or size afterwards. wmctrl窗口,但之后无法更改其位置或大小。

This is reproducible in both the single and triple monitor X screen states. 这在单监视器和三监视器X屏幕状态下都是可重现的。

This problem seems to be not specific to any particular tool. 这个问题似乎并不特定于任何特定工具。 For example, xdotool also fails to change window size/location if the window was just unmaximized but was not moved/resized manually. 例如,如果窗口刚刚未最大化但未手动移动/调整大小,则xdotool也无法更改窗口大小/位置。


The only reliable workaround I have found so far is to unmaximize the window, either manually, with ewmh or with wmctrl , and then manually change the window size or manually move it a bit. 到目前为止,我发现的唯一可靠的解决方法是手动,使用ewmh或使用wmctrl窗口,然后手动更改窗口大小或手动移动它。 Only then I always can move or resize it with ewmh or wmctrl . 只有这样我才能用ewmhwmctrl移动或调整它。 But obviously this is not acceptable solution. 但显然这是不可接受的解决方案。

Is there reliable way to set window geometry even if the window is currently maximized? 即使窗口当前最大化,是否有可靠的方法来设置窗口几何? A method through Python is preferred, but a solution with shell commands will be fine too. 通过Python的方法是首选,但使用shell命令的解决方案也可以。

Thanks to nm comment I found a solution. 感谢nm评论,我找到了解决方案。 Here are relevant parts from my python script (it saves and restores state and geometry of all windows, so this example unmaximizes, unmaps and maps all windows): 以下是我的python 脚本中的相关部分(它保存并恢复所有窗口的状态和几何,因此这个示例取消最大化,取消映射并映射所有窗口):

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

After executing this code it is possible to set window geometry for any window. 执行此代码后,可以为任何窗口设置窗口几何。 all_win is a list of all windows represented as list of custom class objects populated with data from ewmh.getClientList() . all_win是所有窗口的列表,表示为填充了来自ewmh.getClientList()数据的自定义类对象的列表。 Each client.xwin = disp.create_resource_object("window", client.id) . 每个client.xwin = disp.create_resource_object("window", client.id) Waiting for mapping/unmapping to finish is important, otherwise it will be unreliable. 等待映射/取消映射完成很重要,否则它将是不可靠的。 Also, it is necessary to limit poll attempts to prevent infinite loop in case some window gets mapped or unmapped unexpectedly. 此外,有必要限制轮询尝试以防止在某些窗口意外映射或取消映射的情况下无限循环。


If you do not want to reconfigure a lot of windows at once, there is no noticeable performance improvement from using python xlib module for unmapping and mapping, it is easier to use xdotool instead: 如果你不想一次重新配置很多窗口,使用python xlib模块进行取消映射和映射没有明显的性能提升,使用xdotool更容易:

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

If you want to set window geometry in shell script the following example should work even if the window is maximized: 如果要在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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM