窗口’分组’?

我只是想知道,有没有办法’分组’窗户? 我的意思是,有没有办法将两个或多个窗户的边缘连接在一起,这样当一个窗户移动时,另一个移动它,作为一个大窗户? 或者至少类似的地方,移动一个窗口以相同的方式移动另一个窗口? 我正在使用GNOME 3.18运行Ubuntu GNOME 15.10。

未完成的答案; 寻找输入

虽然wmctrl看起来似乎非常可行,但使用wmctrl一如既往,现实比理论更复杂。

我不愿意将此作为答案发布,因为它只是一个实验性的, 概念性的答案,而不是一个现成的解决方案(还有)由于一些错误。 不过我希望能够在当前版本中获得解决问题的一些意见。 这个问题对于进一步开发(IMO)是否足够有趣,以确定是否可以创建平滑的解决方案。

语言:无

虽然我用Python编写了脚本,但语言与我遇到的问题无关; 主要与使用wmctrl

可以使用xdotool来定位窗口,但是由于OP提到将一组窗口移动到另一个工作区,因此wmctrl具有一些优点,特别是在使用Gnome时 ,其中工作区的安排与Unity不同。

它是如何工作的一个例子,移动一组窗口

在此处输入图像描述

将窗户作为一组移动

  • 屏幕演员

以上屏幕中的示例是在Unity上进行的。 然而,它应该在Gnome类似地工作(除了偏差之外,请参阅下面有关脚本的更多内容)。

  • 在当前设置中,可以通过使用以下参数调用下面的脚本,将最前面的窗口添加到组中来创建一组窗口: a 。 在屏幕演员中,我将命令添加到Gnome上的(Unity)启动器,可以使用快捷键完成。
  • 随后,如果在移动其中一个分组窗口后使用参数r调用脚本,则脚本同样从组中移动所有窗口,相对于彼此恢复窗口:

怎么做

  • 使用选项a运行,下面的脚本将当前活动窗口,其位置和大小(如wmctrl -lG输出中的相应行)添加到文件wgroup_data.txt (在~ )。
  • 使用选项r运行,脚本读取文件,查找更改位置的窗口,计算旧位置和新位置之间的向量,并相应地移动其他窗口。
  • 如果窗口关闭,脚本会自动从组列表中删除它。

到目前为止没问题。

问题

但是 ,如果其中一个窗口未完全适合当前工作空间的边框 ,则脚本将失败。 实际上, wmctrl命令失败,因为它也在脚本“外部”失败,作为单个命令运行。

  • 看它何时失败

剧本

 #!/usr/bin/env python3 import subprocess import os import sys arg = sys.argv[1] # vertical deviation for Unity (use 0 for Gnome) deviation = 28 fdata = os.environ["HOME"]+"/wgroup_data.txt" def get_wmctrl(): # try because of buggy wmctrl... try: return subprocess.check_output(["wmctrl", "-lG"]).decode("utf-8") except subprocess.CalledProcessError: pass def remove_window(window): data = open(fdata).readlines() [data.remove(l) for l in data if l.startswith(window)] open(fdata, "wt").write(("").join(data)) def addwindow(): relevant = get_wmctrl() frontmost = hex(int((subprocess.check_output(["xdotool", "getactivewindow"]).decode("utf-8").strip()))) frontmost = frontmost[:2]+str((10-len(frontmost))*"0")+frontmost[2:] open(fdata, "+a").write([l+("\n") for l in get_wmctrl().splitlines() if frontmost in l][0]) print(frontmost) def rearrange(): wlist = get_wmctrl() if wlist != None: group = [(l.strip(), l.split()) for l in open(fdata).read().splitlines() if not l in ("", "\n")] try: changed = [w for w in group if (w[0] in wlist, w[1][0] in wlist) == (False, True)][0] # # only proceed if one of the grouped windows moved (give priority to a light loop if not): follow = [] for w in group: if not w == changed: test = (w[0] in wlist, w[1][0] in wlist) if test == (True, True): follow.append(w) elif test == (False, False): # remove closed window from list remove_window(w[1][0]) # only proceed if there are windows to move: if follow: # find match of the moved window (new coords) wlines = wlist.splitlines() match = [l.split() for l in wlines if changed[1][0] in l][0] # calculate the move vector x_move = int(match[2])-(int(changed[1][2])); y_move = int(match[3])-(int(changed[1][3])) for w in follow: # should be changed to try? w[1][2] = str(int(w[1][2]) + x_move); w[1][3] = str(int(w[1][3]) + y_move - deviation) subprocess.Popen([ "wmctrl", "-ir", w[1][0], "-e", (",").join([w[1][1], w[1][2], w[1][3], w[1][4], w[1][5]]) ]) # update grouplist while True: try: newlines = sum([[l for l in get_wmctrl().splitlines() if w in l] for w in [match[0]]+[item[1][0] for item in follow]], []) open(fdata, "wt").write(("\n").join(newlines)) break except AttributeError: pass except IndexError: print("nothing changed") if arg == "a": addwindow() elif arg == "r": rearrange() 

如何使用

  1. 该脚本需要wmctrlxdotool

     sudo apt-get install xdotool wmctrl 
  2. 将脚本复制到空文件中,将其另存为group_windows.py

  3. 如果你在Gnome:
    在脚本的head部分中,更改行:

     deviation = 28 

     deviation = 0 
  4. 将两个命令添加到不同的快捷方式:

     python3 /path/to/group_windows.py a 

    将窗口添加到组中,以及

     python3 /path/to/group_windows.py r 

    重新排列窗口,如屏幕演员所示

  5. 通过向组添加一些窗口来测试脚本,移动它们并恢复它们的相对位置,如屏幕演员所示。

进一步的发展

这个问题可以通过简单地拒绝移动窗口来解决问题,以防任何窗口出现在当前工作空间之外。 在这种情况下,即使刚刚移动的窗口也应该返回到其初始位置以保持相对位置的活动。

然而,这需要大量的计算(计算机没有,但编码很复杂),并且在当前工作空间之外进行部分定位会更加优雅; 当手动将窗口“放在边缘上或边缘上”时,没有问题。
有关解决这个问题的任何建议都非常受欢迎。