特定のビューポートと位置でアプリケーションウィンドウを開くスクリプト(またはソフトウェア)はありますか?


8

Unityには8つの仮想デスクトップがあり(Compizを使用)、同時に取り組んでいるプロジェクトがたくさんあるので

問題は、Chromeを再起動するか、誤って閉じる必要があるたびに(作業に必要なウィンドウの大部分を占めます)、手動でこれらのウィンドウをもう一度開いて設定する必要があります(ファイルを開いて、正しい場所に移動します) URLなど)。

私のためにすべてを行うスクリプトをどのように書きますか?つまり:1)ウィンドウを開く2)正しい仮想画面で正しい座標に配置する

(1)は明らかです。GoogleChromeの場合は、「google-chrome」を実行するだけです。しかし、それをどのように適切な場所に配置するのでしょうか。(2)

それとも、私のためにそれを実行するスクリプト/ソフトウェアがすでに存在していますか?


起動時に必要なウィンドウを適切なデスクトップに配置するためのスクリプトを作成することもできますが、来週のファイナルがあるので、数日かかるかもしれません。これは、wmctrlスクリプトまたはターミナルを介してウィンドウを制御するためのソフトウェアのようなものです。しかし、ウィンドウの再起動に関しては、それはもう少し難しいかもしれません
セルギー・コロディアズニー

Unityについて具体的に質問しましたが、KDEにはこれを行うkstartと呼ばれる(ほとんどドキュメント化されていない)プログラムがあることは注目に値します。KDEプログラムで最もよく機能しますが、他のプログラムでもある程度成功します。
Joe

回答:


14

これは非常にうまくできますが、Unity /ビューポートについてある程度理解する必要があります。以下の話が理解できるといいのですが、理解できない場合はコメントを残してください。

以下のスクリプトは、任意の位置に、あなたのビューポートのいずれかに任意のアプリケーションのウィンドウを開くために使用することができるならば、あなたが右の引数を指定して、それを実行します。このスクリプトはこれを編集したものですが、これで、スパンする仮想デスクトップにウィンドウを配置する準備ができました。

1.ビューポートとウィンドウ座標を理解する

Unityのワークスペース

Unityでは、他のウィンドウマネージャーとは異なり、実際にはビューポートに分割された1つのスパニングワークスペースしかありません。この場合、ワークスペースは8つのビューポートに分割されます。

ウィンドウの位置の定義方法

コマンドの出力としてのウィンドウ位置:

wmctrl -lG
(you need to have wmctrl installed to run the command)

現在のビューポートの左上隅基準にした位置として記述されます:


したがって、ビューポートにいる場合1
ビューポート2のウィンドウは、たとえば1700(x方向)x 500(y方向)に配置できます
(画面は1680x1050)

ここに画像の説明を入力してください


ただし、ビューポート6を使用している場合:
同じウィンドウが20(x)、-550(y)に配置されます。 ここに画像の説明を入力してください


これらの座標を正しく使用することは、以下で説明するように、正しい引数でスクリプトを実行するために重要です。

2.スクリプトの使用方法

以下のスクリプトを使用して、仮想(スパン)ワークスペースにアプリケーションの新しいウィンドウを配置できます。

  1. wmctrlがインストールされていることを確認してください:

    sudo apt-get install wmctrl
    
  2. 以下のスクリプトを空のファイルにコピーし、setwindow(拡張子なしで)として保存し~/binます。ディレクトリがまだない場合は作成します。スクリプトを実行可能にします

  3. 作成したばかりの場合~/bin、コマンドを実行するsource ~/.profileか、ログアウト/ログインして、でディレクトリを使用できるようにし$PATHます。
  4. コマンドをテスト実行します。

    setwindow <application> <x_position> <y_position> <horizontal_size> <vertical_size>
    

    例えば

    setwindow gedit 100 100 200 200
    

    geditウィンドウが現在のビューポートに表示されます。

ノート:

  • すべてのアプリケーションが特定の幅または高さ以下のウィンドウサイズを許可するわけではないことに注意してください。gedit私のシステムでのウィンドウの最小幅は、たとえばapprです。470ピクセル。
  • スクリプトは、ウィンドウ全体がターゲットのビューポートに収まる場合にのみ正常に機能し、それに応じて座標/サイズを選択します。また、Unityランチャーとパネルはウィンドウの位置に影響を与える可能性があるスペース(!)を使用することにも注意してください。
  • <x_position>現在のビューポートの左側にウィンドウを配置するには、負の値を使用します
  • 負の値<y_position>を使用して、現在のビューポートの上にウィンドウを配置します
  • 異なるビューポートで新しいウィンドウを一度に開くには、コマンドをチェーンするだけです。「Long story」の例のビューポート設定を見て、ビューポート1にいる場合、次のコマンドでビューポート1、2、3、および4でgeditウィンドウを開くことができます。

    setwindow gedit 100 100 200 200&&setwindow gedit 1780 100 200 200&&setwindow gedit 3460 100 200 200&&setwindow gedit 5140 100 200 200
    

スクリプト

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

app = sys.argv[1]

get = lambda x: subprocess.check_output(["/bin/bash", "-c", x]).decode("utf-8")
ws1 = get("wmctrl -lp"); t = 0
subprocess.Popen(["/bin/bash", "-c", app])
# fix exception for Chrome (command = google-chrome-stable, but processname = chrome)
app = "chrome" if "chrome" in app else app
while t < 30:      
    ws2 = [w.split()[0:3] for w in get("wmctrl -lp").splitlines() if not w in ws1]
    procs = [[(p, w[0]) for p in get("ps -e ww").splitlines() \
              if app in p and w[2] in p] for w in ws2]
    if len(procs) > 0:
        w_id = procs[0][0][1]
        cmd1 = "wmctrl -ir "+w_id+" -b remove,maximized_horz"
        cmd2 = "wmctrl -ir "+w_id+" -b remove,maximized_vert"
        cmd3 = "wmctrl -ir "+procs[0][0][1]+" -e 0,"+sys.argv[2]+","+sys.argv[3]+","+sys.argv[4]+","+sys.argv[5]
        for cmd in [cmd1, cmd2, cmd3]:   
            subprocess.call(["/bin/bash", "-c", cmd])
        break
    time.sleep(0.5)
    t = t+1



編集:遅延バージョン

現在のビューポートでウィンドウを開き、ターゲットのビューポートを引数として(何も計算する必要なしに)与えるかのように、座標とサイズを入力するだけの場合は、以下のバージョンを使用します...

スクリプトの最初のバージョンのように設定した場合は、次のコマンドで実行できます。

setwindow <application> <x_position> <y_position> <horizontal_size> <vertical_size> <targeted_viewport>

例:ビューポートGoogle-Chrome上の20, 20、サイズ300x300に配置されたウィンドウを開くには5

setwindow google-chrome 20 20 300 300 5

設定はスクリプトの最初のバージョンとほとんど同じです。
また、このスクリプトは、定義されたウィンドウ(位置/サイズ)がターゲットビューポート内に完全に収まる場合にのみ正しく機能することに注意してください。

スクリプト:

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

app = sys.argv[1]
target_vp = int(sys.argv[6])

def get_res():
    # get resolution
    xr = subprocess.check_output(["xrandr"]).decode("utf-8").split()
    pos = xr.index("current")
    return [int(xr[pos+1]), int(xr[pos+3].replace(",", "") )]

res = get_res()

def current(set_vp):
    # get the current viewport
    vp_data = subprocess.check_output(
        ["wmctrl", "-d"]
        ).decode("utf-8").split()
    dt = [int(n) for n in vp_data[3].split("x")]
    cols = int(dt[0]/res[0])
    rows = int(dt[1]/res[1])    
    curr_vpdata = [int(n) for n in vp_data[5].split(",")]
    curr_col = int(curr_vpdata[0]/res[0])
    curr_row = int(curr_vpdata[1]/res[1])
    curr_vp = curr_col+curr_row*cols+1
    # calculate the vector to the origin from the current viewport (in resolution units)
    vec_curr = vector(curr_vp, cols)
    # calculate the vector to the origin from the targeted viewport
    vec_set = vector(set_vp, cols)
    # calculate the vector between current and targeted viewport
    vec_relative = [vec_set[0] - vec_curr[0],
                    vec_set[1] - vec_curr[1]]
    # calculate needed correction (absolute)
    relative = [vec_relative[0]*res[0],
                vec_relative[1]*res[1]]
    return relative

def vector(vp, cols):
    rem = vp%cols
    vec_x = rem-1 if rem != 0 else cols-1
    vec_y = int((vp-1)/cols)
    return [vec_x, vec_y]

res = get_res() # nieuw
get = lambda x: subprocess.check_output(["/bin/bash", "-c", x]).decode("utf-8")
ws1 = get("wmctrl -lp"); t = 0
# check for additional arguments to run the application
try:
    subprocess.Popen(["/bin/bash", "-c", app+" "+sys.argv[7]])  
except IndexError:
    subprocess.Popen(["/bin/bash", "-c", app])

# fix exception for Chrome (command = google-chrome-stable, but processname = chrome)
app = "chrome" if "chrome" in app else app
while t < 30:      
    ws2 = [w.split()[0:3] for w in get("wmctrl -lp").splitlines() if not w in ws1]
    procs = [[(p, w[0]) for p in get("ps -e ww").splitlines() \
              if app in p and w[2] in p] for w in ws2]
    if len(procs) > 0:
        w_id = procs[0][0][1]
        cmd1 = "wmctrl -ir "+w_id+" -b remove,maximized_horz"
        cmd2 = "wmctrl -ir "+w_id+" -b remove,maximized_vert"
        # calculate the correction, related to the current workspace, marge for launcher and panel
        pos_x = int(sys.argv[2]); pos_y = int(sys.argv[3]); x_marge = 65; y_marge = 35
        pos_x = pos_x if pos_x > x_marge else x_marge; pos_y = pos_y if pos_y > y_marge else y_marge
        x_relative = pos_x+current(target_vp)[0]
        y_relative = pos_y+current(target_vp)[1]
        # correct possible inaccurately set width / height
        x_size = res[0]; y_size = res[1]
        set_width = int(sys.argv[4]); set_height = int(sys.argv[5])
        width = set_width if set_width+x_marge+pos_x < x_size else x_size - pos_x - x_marge
        height = set_height if set_height+y_marge+pos_y < y_size else y_size - pos_y - y_marge
        cmd3 = "wmctrl -ir "+w_id+" -e 0,"+str(x_relative)+","+str(y_relative)+","+str(width)+","+str(height)
        for cmd in [cmd1, cmd2, cmd3]:   
            subprocess.call(["/bin/bash", "-c", cmd])
        break
    time.sleep(0.5)
    t = t+1


引数を使用してアプリケーションウィンドウを開く

仕事を完了するには、質問に完全に答えます。

たとえば次のようにスクリプトを実行した場合:

setwindow google-chrome 20 20 300 300 5

ターゲットのデスクトップにデフォルトのウィンドウが開きます
しかし、スクリプトの最新バージョンでは、あなたがすることができます追加、追加の例Aについて、アプリケーションウィンドウを開くには、引数をurl

setwindow <application> <x_position> <y_position> <horizontal_size> <vertical_size> <targeted_viewport> <(optional)_argument>

例えば:

setwindow google-chrome 0 0 600 600 3 "--new-window http://askubuntu.com"

(追加)引数にスペースが含まれている場合は、引用符を使用します。上記の例ではgoogle-chrome、ビューポート3でウィンドウを開き、を開きますurl http://askubuntu.com

コマンドをチェーンして、1つのコマンドで複数のウィンドウ/ URLを異なるワークスペースで開くことができます。例:

setwindow google-chrome 0 0 600 600 8 "--new-window http://askubuntu.com"&&setwindow google-chrome 0 0 600 600 7 "--new-window www.google.com"

@snitkoいい質問をありがとう、それを成し遂げるのはいい挑戦だった:)
Jacob Vlijm

スクリプトを使用しているときに、ウィンドウにわずかなオフセットがあることに気付きました。したがって、たとえば、座標0 0で開くと、実際には少し右と下に開きます(約10pxのオフセット)。それは問題ありませんが、問題は実際には2番目のスクリプトにあります。2番目のスクリプトのオフセットは、横軸で奇妙に大きくなっています。左に約50pxだと思います。なぜか分かりますか?その場合、負の座標を設定しても効果はありません。
snitko

別の質問:ウィンドウをフルスクリーンで開くにはどうすればよいですか?
snitko

更新:2番目のスクリプトの場合のオフセットは、左側のユニティドックの幅と同じであるように見えます(非表示ですが)。
snitko

興味のある方のために、私はDesktopenを実装しました:github.com/snitko/desktopen
snitko

1

これは、@ Jacob Vlijimの上記の素晴らしい答えを少し修正したsetwindowスクリプトで拡張したものです

#!/usr/bin/env python

import time
import argparse
import subprocess

DEFAULT_WIDTH = '1920'
DEFAULT_HEIGHT = '1080'


def get_window_list():
    window_list = subprocess.check_output(['/bin/bash', '-c', 'wmctrl -l'])
    parsed_list = []
    for line in window_list.splitlines():
        window_info = line.split()
        if window_info[1] != '-1':
            parsed_list.append(window_info[0])
    return parsed_list


def main(params):
    old_list = get_window_list()
    subprocess.Popen(['/bin/bash', '-c', params.command])

    def get_diff(old):
        new_list = get_window_list()
        return list(set(new_list) - set(old))

    diff = get_diff(old_list)
    x = 0
    while not diff:
        if x == 10:
            print 'window not found'
            return
        x += 1
        diff = get_diff(old_list)
        time.sleep(1)
    if len(diff) > 1:
        raise Exception(diff)
    window_id = diff[0]
    command_list = []
    command_list.append('wmctrl -ir %s -t %s' % (window_id, params.desktop))
    command_list.append('wmctrl -ir %s -b remove,maximized_horz,maximized_vert'
        % window_id)
    command_list.append('wmctrl -ir %s -e 0,%s,%s,%s,%s' %
        (window_id, params.x_pos, params.y_pos, params.width, params.height))
    for command in command_list:
        subprocess.call(['/bin/bash', '-c', command])

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('command', type=str)
    parser.add_argument('-d', '--desktop', default='0', type=str)
    parser.add_argument('-x', '--x-pos', default='0', type=str)
    parser.add_argument('-y', '--y-pos', default='0', type=str)
    parser.add_argument('-w', '--width', default=DEFAULT_WIDTH, type=str)
    parser.add_argument('-t', '--height', default=DEFAULT_HEIGHT, type=str)
    args = parser.parse_args()
    main(args)

変更の説明:

  1. python3python(単なる個人的な好み)
  2. sys.argvargparse優れたコマンドラインインタフェースのための
  3. 厳密なウィンドウID(プロセスIDではない)ウィンドウ解析
    • 一部のプログラムは複数のウィンドウに対して単一のプロセスIDを使用します
  4. while 0.5秒から1秒のスリープ時間でループ
  5. より冗長で読みやすい変数名とpep8の順守
  6. xrandr依存ではなく画面サイズのグローバル定数変数

注:これは、Debian Jessie LXDEで個人的に使用するために私が書いたわずかに改善されたバージョンです。結果は異なる場合があります。


0

興味のある方のために、Desktopenを実装しました:github.com/snitko/desktopen

さまざまなビューポートでウィンドウを開いたり、非常に親しみやすい方法で表示したりするためのスクリプトを記述できます。

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