web-dev-qa-db-ja.com

特定のアプリケーションのウィンドウがフォーカスを失ったときに、最も低いZ位置に自動的に送信できますか?

ほとんどの作業は、Webブラウザーとエディターの2つのアプリケーションで行います。私はAlt-Tabで頻繁にそれらの間を行き来します。また、常にIMクライアント(Hipchat)を開いていますが、他の2つのアプリと比較して操作することはほとんどありません。

繰り返し発生する不快な点は、Hipchatウィンドウを操作してAlt-Tabを(たとえば)エディターに戻した後、別のAlt-Tabがブラウザーに集中することを期待するように筋肉のメモリが調整され、再びHipchatに戻ることです。

Hipchatが何らかの方法でフォーカスを失った後、スタックまたはリーセンシーリストの一番下、またはそれが何であれ送信されるようにする方法はありますか?

3
Sean

あなたが尋ねるのは、特定のアプリケーションのウィンドウがonlyを最初または最後に表示できるようにすることです位置、z方向。

geditウィンドウ(この例では)がフォーカスを失うと、1つの位置だけを降下するのではなく、最後の位置(z方向、半透明のターミナルウィンドウの下)に送信されます

enter image description hereenter image description here


ウィンドウのZ位置

それは可能ですが、いくつかの深刻な問題を克服する必要があります。ウィンドウが最後の位置に送られると、他のすべてのウィンドウのZオーダーを維持する必要があります。ただし、現在のところ、このzオーダーのウィンドウを提供できるツールはありません。 xdotoolwmctrlのどちらも、これに関する情報を提供していません。

ただし、(すべての)ウィンドウのフォーカス履歴を追跡することができます。別のウィンドウがフォーカスを取得すると、ウィンドウは1つの位置を下るので、バックグラウンドスクリプトを実行してウィンドウのフォーカス履歴を監視すると、ウィンドウのzオーダーを結論付けることができます。

ソリューション2つの小さなバックグラウンドスクリプト

以下のソリューションは、同時に実行する2つの小さなバックグラウンドスクリプトで構成されています。

  1. フォーカス履歴を追跡するスクリプト:focus_history.py
  2. ターゲットアプリケーションのウィンドウがフォーカスを失った場合、最後の位置に移動するスクリプト:set_z.py

スクリプト1

focus-history.py

#!/usr/bin/env python3
import subprocess
import time
import os

rootdata = os.environ["HOME"]+"/.focus_history"
open(rootdata, "wt").write("This is an empty line")

def current_windows():
    try:
        return subprocess.check_output(["wmctrl", "-lp"]).decode("utf-8")
    except subprocess.CalledProcessError:
        pass

def convert_format(w_id):
    return w_id[:2]+(10-len(w_id))*"0"+w_id[2:]

def read_data():
    return open(rootdata).read().splitlines()

def get_top(wlist):
    try:
        top = convert_format(
            [l.split("#")[-1].strip() for l in subprocess.check_output(
                ["xprop", "-root"]
                ).decode("utf-8").splitlines() \
               if "_NET_ACTIVE_WINDOW(WINDOW)" in l][0])
        return [l for l in wlist if top in l][0]
    except IndexError:
        pass

if __name__ == "__main__":
    while True:
        time.sleep(1)
        wdata = current_windows()
        if wdata != None:
            wlist = wdata.splitlines()
            # get frontmost window (as in wmctrl -lG)
            top = get_top(wlist)
            oldlist = read_data()
            if not any([top == oldlist[0], top == None]):
                # clean up closed windows
                [oldlist.remove(l) for l in oldlist if not l.split()[0] in wdata]
                # remove possible other mentions of the active window
                [oldlist.remove(l) for l in oldlist if l.startswith(top.split()[0])]
                open(rootdata, "wt").write(("\n").join([top]+oldlist))

スクリプト2

#!/usr/bin/python3
import subprocess
import time
import focus_history

# --- set the process name of your application below
proc = "gedit"
# ---

focus_hist = focus_history.rootdata

def get(val):
    try:
        return subprocess.check_output(val).decode("utf-8").strip()
    except subprocess.CalledProcessError:
        pass

def front_w():
    get_front = str(hex(int(get(["xdotool", "getactivewindow"]))))
    return get_front[:2]+(10-len(get_front))*"0"+get_front[2:]

while True:
    time.sleep(1)
    pid = get(["pgrep", proc])
    front1 = ""
    while pid:
        time.sleep(1)
        frontpid = get(["xdotool", "getactivewindow", "getwindowpid"])
        front2 = frontpid == pid
        if front2 != front1:
            if front2 == False:
                zdata = [l for l in open(focus_hist).read().splitlines()]
                wins = list(reversed([l.split()[0] for l in zdata if not pid in l]))
                for w in wins+[front_w()]:
                    cmd = ["xdotool", "windowraise", w]
                    subprocess.call(cmd)
        pid = get(["pgrep", proc])            
        front1 = front2

設定方法

  1. スクリプトはwmctrlxdotoolの両方を使用します

    Sudo apt-get install wmctrl xdotool
    
  2. スクリプト1を空のファイルにコピーし、focus_history.pyとして(正確に)保存します

  3. スクリプト2を空のファイルにコピーし、set_z.pyとしてまったく同じディレクトリに保存しますスクリプト1として。

    スクリプトのヘッドセクションの次の行:

    proc = "gedit"
    

    "gedit"をアプリケーションのプロセス名に置き換えます(引用符の間)

  4. スクリプトのテスト実行:(追加の)ウィンドウを開く前に、コマンドでスクリプト1を起動します:

    python3 /path/to/focus_history.py & python3 /path/to/set_z.py
    

    [スクリプトは、少なくとも1回フォーカスされたウィンドウを認識します。ログイン時にスクリプトが実行される場合はそうなります]

    前述のように、スクリプトは同じレベルの同じディレクトリにある必要があります。

  5. 次に、ウィンドウを開いて、その動作を確認します。アプリケーションは、フォーカスを失った場合、(非常に)バックグラウンドに移動する必要があります。

  6. すべてが正常に機能する場合は、それをスタートアップアプリケーションに追加します。ダッシュ>スタートアップアプリケーション>追加。次のコマンドを追加します。

    /bin/bash -c "sleep 15 && python3 /path/to/focus_history.py & python3 /path/to/set_z.py"
    

ノート

  • セットアップは、ターゲットアプリケーションのsingleウィンドウが開いていることを前提としています。あなたの質問から、私はそれが事実であることを理解しています。

あるいは

別の方法として、 here で説明されているように、ショートカットキーを設定して、特定のアプリケーションのウィンドウが存在する場合はそれを表示することもできます。

ただし、最初のアプリケーションのウィンドウに戻るには別のショートカットが必要です。

を除いて...、

2つのアプリケーションを切り替える1つのショートカットを設定します。しかし、それはこの質問の範囲外です...

3
Jacob Vlijm