AとBの2つのウィンドウがあります。Aに切り替えるとBが発生するように、またはBに切り替えるとAも発生するように、2つのウィンドウをリンクすることは可能ですか?
複数のワークスペースを使用することも選択肢の1つだと理解していますが、これも可能かどうか疑問に思いましたか。
AとBの2つのウィンドウがあります。Aに切り替えるとBが発生するように、またはBに切り替えるとAも発生するように、2つのウィンドウをリンクすることは可能ですか?
複数のワークスペースを使用することも選択肢の1つだと理解していますが、これも可能かどうか疑問に思いましたか。
回答:
次のスクリプトでは、2つのウィンドウを選択できます。両方のウィンドウが開いているときに、ユーザーがいずれか1つにフォーカスすると、両方のウィンドウが表示されます。たとえば、ある人が未亡人AとBをリンクしている場合、AまたはBのいずれかにウィッチングすると、両方が他の未亡人よりも高くなります。
スクリプトを停止するにkillall link_windows.py
は、ターミナルで使用するか、ウィンドウの1つを閉じて再度開きます。Xいずれかのウィンドウ選択ポップアップダイアログの閉じるボタンを押して、実行をキャンセルすることもできます。
潜在的な調整:
次のようにスクリプトを実行します。
python link_windows.py
スクリプトはPython 3と互換性があるため、次のように実行することもできます
python3 link_windows.py
2つのコマンドラインオプションがあります。
--quiet
または-q
、GUIウィンドウを沈黙させることができます。このオプションを使用すると、任意の2つのウィンドウをマウスでクリックするだけで、スクリプトがそれらのリンクを開始します。--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
。ここで./
、スクリプトと同じディレクトリにいる必要があることを示しています。
2つのウィンドウの簡単な使用プロセス:
ウィンドウ#1を選択するOKか、を押すか押すかを尋ねるポップアップが表示されますEnter。マウスポインタが十字に変わります。リンクするウィンドウの1つをクリックします。
2番目のポップアップが表示され、ウィンドウ#2を選択するか、を押すOKか押すかを尋ねられますEnter。再び、マウスポインターが十字に変わります。リンクする他のウィンドウをクリックします。その後、実行が始まります。
どちらかのウィンドウにフォーカスすると、スクリプトによってもう一方のウィンドウが上に移動しますが、フォーカスは最初に選択したウィンドウに戻ります(注-最高のパフォーマンスを得るには1/4秒の遅延があります)。
同じウィンドウを両方選択すると、スクリプトは終了します。ポップアップダイアログの閉じるボタンをクリックすると、スクリプトが終了します。
GitHub Gistとしても利用可能
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Author: Sergiy Kolodyazhnyy
Date: August 2nd, 2016
Written for: /ubuntu//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.
されます。これらは無視できます。time.sleep
切り替えの間のビット、私はそれをゼロにすることができますか?遅延の理由はありますか?
# time.sleep(0.25)
と、実行されません。これは、各ウィンドウが適切に表示されるようにするためです。私の過去の経験では、Windowsでの操作に遅延が必要でした。私は四分の一秒の遅延はそれほどではないと思います。実際、スクリプトに1行だけ追加すると、スピードアップできます。OK ?
以下の解決策では、2つ、3つ、またはそれ以上のウィンドウの任意の組み合わせを選択して、キーボードショートカットを使用して1つのウィンドウとして組み合わせることができます。
スクリプトは3つの引数を使用して機能します。
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
スクリプトをテスト実行します。2つのターミナルウィンドウを開き、次のコマンドを実行します。
python3 /absolute/path/to/groupwindows.py add
それらの両方で。それらを他のウィンドウで覆う(または最小化する)。3番目のターミナルウィンドウを開き、次のコマンドを実行します。
python3 /absolute/path/to/groupwindows.py raise
最初の2つのウィンドウは1つに引き上げられます。
すべてが正常に機能する場合は、3つのカスタムショートカットキーを作成します。[システム設定]> [キーボード]> [ショートカット]> [カスタムショートカット]を選択します。「+」をクリックして、以下のコマンドを3つの個別のショートカットに追加します。
私のシステムでは、次を使用しました:
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
スクリプトはアクティブウィンドウのウィンドウIDを非表示ファイルに保存/追加します~/.windowlist
引数を指定して実行すると、raise
スクリプトはファイルを読み取り、次のコマンドでリスト内のウィンドウを表示します。
wmctrl -ia <window_id>
clear
スクリプトは隠しファイルを削除します~/.windowlist
。前述のように、上記のスクリプトでは、グループ化されたウィンドウにいつでもウィンドウを追加できます。以下のバージョンでは、グループ化されたリストから(いつでも)ウィンドウを削除することもできます。
#!/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をショートカットとして設定します。