ウィンドウを1つにグループ化するにはどうすればよいですか?


10

AとBの2つのウィンドウがあります。Aに切り替えるとBが発生するように、またはBに切り替えるとAも発生するように、2つのウィンドウをリンクすることは可能ですか?

複数のワークスペースを使用することも選択肢の1つだと理解していますが、これも可能かどうか疑問に思いましたか。


zオーダーはそれほど重要ではありませんが、できればそれはすばらしいでしょう
Simon Tong

複数の作業場が最も簡単な解決策だと思います。それらを切り替えるためのキーの組み合わせを知っていますか?
thomasrutter 2016

1
あなたはすぐに受け入れます:)それにもかかわらず、私の答えにコメントを付けていただければ幸いです。
Jacob Vlijm 16

回答:


9

前書き

次のスクリプトでは、2つのウィンドウを選択できます。両方のウィンドウが開いているときに、ユーザーがいずれか1つにフォーカスすると、両方のウィンドウが表示されます。たとえば、ある人が未亡人AとBをリンクしている場合、AまたはBのいずれかにウィッチングすると、両方が他の未亡人よりも高くなります。

スクリプトを停止するにkillall link_windows.pyは、ターミナルで使用するか、ウィンドウの1つを閉じて再度開きます。Xいずれかのウィンドウ選択ポップアップダイアログの閉じるボタンを押して、実行をキャンセルすることもできます。

潜在的な調整:

  • スクリプトの複数のインスタンスを使用して、2つのウィンドウのペアをグループ化できます。たとえば、ウィンドウA、B、C、Dがある場合、AとBをリンクし、CとDをリンクできます。
  • 複数のウィンドウを1つのウィンドウにまとめることができます。たとえば、ウィンドウBをAに、CをAに、DをAにリンクすると、常にAに切り替えると、4つのウィンドウすべてを同時に上げることができます。

使用法

次のようにスクリプトを実行します。

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. ウィンドウ#1を選択するOKか、を押すか押すかを尋ねるポップアップが表示されますEnter。マウスポインタが十字に変わります。リンクするウィンドウの1つをクリックします。

  2. 2番目のポップアップが表示され、ウィンドウ#2を選択するか、を押すOKか押すかを尋ねられますEnter。再び、マウスポインターが十字に変わります。リンクする他のウィンドウをクリックします。その後、実行が始まります。

  3. どちらかのウィンドウにフォーカスすると、スクリプトによってもう一方のウィンドウが上に移動しますが、フォーカスは最初に選択したウィンドウに戻ります(注-最高のパフォーマンスを得るには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()

ノート:


乾杯本当に感動しました。time.sleep切り替えの間のビット、私はそれをゼロにすることができますか?遅延の理由はありますか?
Simon Tong

1
@simontongのようにその行をコメント化してみる# time.sleep(0.25)と、実行されません。これは、各ウィンドウが適切に表示されるようにするためです。私の過去の経験では、Windowsでの操作に遅延が必要でした。私は四分の一秒の遅延はそれほどではないと思います。実際、スクリプトに1行だけ追加すると、スピードアップできます。OK ?
Sergiy Kolodyazhnyy 16

@simontong OK、スクリプトを更新しました。やってみよう。より高速な切り替えが必要
Sergiy Kolodyazhnyy

@simontongいくつかの機能を追加するために、いくつかのマイナーな追加でスクリプトを更新します。準備ができたらお知らせします。ご
意見を

@simontongがスクリプトに追加オプションを追加しました。確認してください
Sergiy Kolodyazhnyy

6

任意の数のウィンドウを1つに上げる

以下の解決策では、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)

使い方

  1. スクリプトにはwmctrlxdotool次のものが必要です。

    sudo apt-get install wmctrl xdotool
  2. 上記のスクリプトを空のファイルにコピーし、次の名前で保存します groupwindows.py
  3. スクリプトをテスト実行します。2つのターミナルウィンドウを開き、次のコマンドを実行します。

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

    それらの両方で。それらを他のウィンドウで覆う(または最小化する)。3番目のターミナルウィンドウを開き、次のコマンドを実行します。

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

    最初の2つのウィンドウは1つに引き上げられます。

  4. すべてが正常に機能する場合は、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

ノート

  • スクリプトは最小化されたウィンドウでも機能し、最小化されている可能性のあるウィンドウの最小化を解除します
  • ウィンドウのセットが別のビューポートにある場合、スクリプトは対応するビューポートに切り替えます
  • セットは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をショートカットとして設定します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.