如何将窗口分组为一个窗口?

我有两个窗口,A和B.是否有可能以某种方式将两个窗口连接在一起,这样切换到A也会提升B,或切换到B也会提升A?

我理解使用多个工作区是另一种选择但是想知道这是否也可能?

介绍

以下脚本允许选择两个窗口,当两个窗口都打开时,当用户聚焦任何一个窗口时,它将引发两个窗口。 例如,如果一个人将寡妇A和B联系起来,那么对A或B的任何威胁都会使其高于其他寡妇。

要停止脚本,您可以在终端中使用killall link_windows.py ,或者关闭并重新打开其中一个窗口。 您也可以通过在任一窗口选择弹出对话框中按关闭按钮X来取消执行。

潜在的调整:

  • 脚本的多个实例可用于对两个窗口的对进行分组。 例如,如果我们有窗口A,B,C和D,我们可以将A和B链接在一起,并将C和D链接在一起。
  • 多个窗口可以分组在一个窗口下。 例如,如果我将窗口B链接到A,C到A和D到A,这意味着如果我总是切换到A,我可以同时提升所有4个窗口。

用法

运行脚本为:

 python link_windows.py 

该脚本与Python 3兼容,因此它也可以作为

 python3 link_windows.py 

有两个命令行选项:

  • --quiet-q ,允许沉默GUI窗口。 使用此选项,您只需在任意两个窗口上单击鼠标,脚本就会开始链接它们。
  • --help-h ,打印用法和描述信息。

-h选项生成以下信息:

 $ python3 link_windows.py -h usage: link_windows.py [-h] [--quiet] Linker for two X11 windows.Allows raising two user selected windows together optional arguments: -h, --help show this help message and exit -q, --quiet Blocks GUI dialogs. 

可以通过pydoc ./link_windows.py查看其他技术信息,其中./表示您必须与脚本位于同一目录中。

两个窗口的简单使用过程:

  1. 将出现一个弹出窗口,要求您选择一个窗口#1,按OK或按Enter键 。 鼠标指针将变为十字形。 单击要链接的其中一个窗口。

  2. 将出现第二个弹出窗口,要求您选择窗口#2,按OK或按Enter键 。 同样,鼠标指针将变为十字形。单击要链接的另一个窗口。 之后执行将开始。

  3. 无论何时聚焦任一窗口,脚本都会向上抬起另一个窗口,但将焦点返回到最初选择的窗口(注意 – 延迟时间为四分之一秒以获得最佳性能),从而产生将窗口链接在一起的感觉。

如果您同时选择同一窗口,脚本将退出。 如果您在任何时候单击弹出对话框的关闭按钮,脚本将退出。

脚本来源

也可以作为GitHub Gist

 #!/usr/bin/env python # -*- coding: utf-8 -*- """ Author: Sergiy Kolodyazhnyy Date: August 2nd, 2016 Written for: https://askubuntu.com/q/805515/295286 Tested on Ubuntu 16.04 LTS """ import gi gi.require_version('Gdk', '3.0') gi.require_version('Gtk', '3.0') from gi.repository import Gdk, Gtk import time import subprocess import sys import argparse def run_cmd(cmdlist): """ Reusable function for running shell commands""" try: stdout = subprocess.check_output(cmdlist) except subprocess.CalledProcessError: sys.exit(1) else: if stdout: return stdout def focus_windows_in_order(first, second, scr): """Raise two user-defined windows above others. Takes two XID integers and screen object. Window with first XID will have the focus""" first_obj = None second_obj = None for window in scr.get_window_stack(): if window.get_xid() == first: first_obj = window if window.get_xid() == second: second_obj = window # When this function is called first_obj is alread # raised. Therefore we must raise second one, and switch # back to first second_obj.focus(int(time.time())) second_obj.get_update_area() # time.sleep(0.25) first_obj.focus(int(time.time())) first_obj.get_update_area() def get_user_window(): """Select two windows via mouse. Returns integer value of window's id""" window_id = None while not window_id: for line in run_cmd(['xwininfo', '-int']).decode().split('\n'): if 'Window id:' in line: window_id = line.split()[3] return int(window_id) def main(): """ Main function. This is where polling for window stack is done""" # Parse command line arguments arg_parser = argparse.ArgumentParser( description="""Linker for two X11 windows.Allows raising """ + """two user selected windows together""") arg_parser.add_argument( '-q','--quiet', action='store_true', help='Blocks GUI dialogs.', required=False) args = arg_parser.parse_args() # Obtain list of two user windows user_windows = [None, None] if not args.quiet: run_cmd(['zenity', '--info', '--text="select first window"']) user_windows[0] = get_user_window() if not args.quiet: run_cmd(['zenity', '--info', '--text="select second window"']) user_windows[1] = get_user_window() if user_windows[0] == user_windows[1]: run_cmd( ['zenity', '--error', '--text="Same window selected. Exiting"']) sys.exit(1) screen = Gdk.Screen.get_default() flag = False # begin watching for changes in window stack while True: window_stack = [window.get_xid() for window in screen.get_window_stack()] if user_windows[0] in window_stack and user_windows[1] in window_stack: active_xid = screen.get_active_window().get_xid() if active_xid not in user_windows: flag = True if flag and active_xid == user_windows[0]: focus_windows_in_order( user_windows[0], user_windows[1], screen) flag = False elif flag and active_xid == user_windows[1]: focus_windows_in_order( user_windows[1], user_windows[0], screen) flag = False else: break time.sleep(0.15) if __name__ == "__main__": main() 

笔记:

  • 从命令行运行时,弹出对话框会产生以下消息: Gtk-Message: GtkDialog mapped without a transient parent. This is discouraged. Gtk-Message: GtkDialog mapped without a transient parent. This is discouraged. 这些可以忽略。
  • 咨询如何手动编辑/创建Unity中的新启动器项目? 如果您希望通过双击启动它,则可以为此脚本创建启动器或桌面快捷方式
  • 要将此脚本链接到键盘快捷键以便于访问,请参阅如何添加键盘快捷键?

将任意数量的窗口提升为一个

下面的解决方案将允许您选择两个,三个或更多窗口的任意组合,以组合和提升为一个键盘快捷方式。

该脚本使用三个参数来完成它的工作:

 add 

将活动窗口添加到组

 raise 

提升集团

 clear 

清除组,准备定义一个新组

剧本

 #!/usr/bin/env python3 import sys import os import subprocess wlist = os.path.join(os.environ["HOME"], ".windowlist") arg = sys.argv[1] if arg == "add": active = subprocess.check_output([ "xdotool", "getactivewindow" ]).decode("utf-8").strip() try: currlist = open(wlist).read() except FileNotFoundError: currlist = [] if not active in currlist: open(wlist, "a").write(active + "\n") elif arg == "raise": group = [w.strip() for w in open(wlist).readlines()] [subprocess.call(["wmctrl", "-ia", w]) for w in group] elif arg == "clear": os.remove(wlist) 

如何使用

  1. 该脚本需要wmctrlxdotool

     sudo apt-get install wmctrl xdotool 
  2. 将上面的脚本复制到一个空文件中,将其另存为groupwindows.py
  3. 测试运行脚本:打开两个终端窗口,运行命令:

     python3 /absolute/path/to/groupwindows.py add 

    在他们两个。 用其他窗户盖住它们(或最小化它们)。 打开第三个终端窗口,运行命令:

     python3 /absolute/path/to/groupwindows.py raise 

    前两个窗口将被提升为一个窗口。

  4. 如果一切正常,请创建三个自定义快捷键:选择:系统设置>“键盘”>“快捷方式”>“自定义快捷方式”。 单击“+”并将以下命令添加到三个单独的快捷方式:

    在我的系统上,我用过:

    Alt + A ,运行命令:

     python3 /absolute/path/to/groupwindows.py add 

    …向组添加窗口。

    Alt + R ,运行命令:

     python3 /absolute/path/to/groupwindows.py raise 

    ……提升小组

    Alt + C ,运行命令:

     python3 /absolute/path/to/groupwindows.py clear 

    ……清理小组

说明

该脚本非常简单:

  • 当使用参数add运行时,脚本将活动窗口的window-id存储/添加到隐藏文件~/.windowlist
  • 当使用参数raise运行时,脚本将读取文件,使用以下命令引发列表中的窗口:

     wmctrl -ia  
  • 使用参数clear运行时,脚本将删除隐藏文件~/.windowlist

笔记

  • 该脚本还可以在最小化的窗口上工作,它可以最小化可能最小化的窗口
  • 如果该组窗口位于另一个视口上,则该脚本将切换到相应的视口
  • 该集是flexibel,您始终可以将其他窗口添加到当前集。

更灵活?

如上所述,上面的脚本允许随时向分组窗口添加窗口。 下面的版本还允许从分组列表中删除任何窗口(在任何时候):

 #!/usr/bin/env python3 import sys import os import subprocess wlist = os.path.join(os.environ["HOME"], ".windowlist") arg = sys.argv[1] # add windows to the group if arg == "add": active = subprocess.check_output([ "xdotool", "getactivewindow" ]).decode("utf-8").strip() try: currlist = open(wlist).read() except FileNotFoundError: currlist = [] if not active in currlist: open(wlist, "a").write(active + "\n") # delete window from the group if arg == "delete": try: currlist = [w.strip() for w in open(wlist).readlines()] except FileNotFoundError: pass else: currlist.remove(subprocess.check_output([ "xdotool", "getactivewindow"]).decode("utf-8").strip()) open(wlist, "w").write("\n".join(currlist)+"\n") # raise the grouped windows elif arg == "raise": group = [w.strip() for w in open(wlist).readlines()] [subprocess.call(["wmctrl", "-ia", w]) for w in group] # clear the grouped window list elif arg == "clear": os.remove(wlist) 

运行脚本的附加参数是delete ,因此:

 python3 /absolute/path/to/groupwindows.py delete 

从分组的窗口中删除活动窗口。 要在我的系统上运行此命令,我将Alt + D设置为快捷方式。