如何将窗口分组为一个窗口?
我有两个窗口,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,按OK或按Enter键 。 鼠标指针将变为十字形。 单击要链接的其中一个窗口。
-
将出现第二个弹出窗口,要求您选择窗口#2,按OK或按Enter键 。 同样,鼠标指针将变为十字形。单击要链接的另一个窗口。 之后执行将开始。
-
无论何时聚焦任一窗口,脚本都会向上抬起另一个窗口,但将焦点返回到最初选择的窗口(注意 – 延迟时间为四分之一秒以获得最佳性能),从而产生将窗口链接在一起的感觉。
如果您同时选择同一窗口,脚本将退出。 如果您在任何时候单击弹出对话框的关闭按钮,脚本将退出。
脚本来源
也可以作为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)
如何使用
-
该脚本需要
wmctrl
和xdotool
:sudo apt-get install wmctrl xdotool
- 将上面的脚本复制到一个空文件中,将其另存为
groupwindows.py
-
测试运行脚本:打开两个终端窗口,运行命令:
python3 /absolute/path/to/groupwindows.py add
在他们两个。 用其他窗户盖住它们(或最小化它们)。 打开第三个终端窗口,运行命令:
python3 /absolute/path/to/groupwindows.py raise
前两个窗口将被提升为一个窗口。
-
如果一切正常,请创建三个自定义快捷键:选择:系统设置>“键盘”>“快捷方式”>“自定义快捷方式”。 单击“+”并将以下命令添加到三个单独的快捷方式:
在我的系统上,我用过:
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设置为快捷方式。