Existe um script (ou software) para abrir uma janela de aplicativo em uma viewport e posição específicas?

8

Portanto, tenho 8 desktops virtuais no Unity (com o Compiz) porque tenho muitos projetos em que estou trabalhando simultaneamente.

O problema é que toda vez que eu preciso reiniciar ou fechar acidentalmente o Chrome (que constitui uma grande parte das janelas que eu preciso para trabalhar) eu tenho que abrir manualmente as janelas novamente e depois configurá-las (abrir arquivos, ir às urls corretas, etc.).

Como você escreveria um roteiro que fará tudo isso por mim? Ou seja: 1) Abra as janelas 2) Coloque-as nas coordenadas corretas nas telas virtuais corretas

(1) é óbvio, para o Google Chrome, basta executar o 'google-chrome'. Mas então como você coloca isso no lugar certo? (2)

Ou existe um script / software que já existe para mim?

    
por snitko 10.05.2015 / 03:13

3 respostas

14

Isso pode ser feito muito bem, mas você precisa de um pouco de compreensão sobre Unity / viewports. Espero que a história abaixo seja compreensível, se não, por favor deixe um comentário.

O script abaixo pode ser usado para abrir uma janela de qualquer aplicativo em qualquer um dos seus viewports, em qualquer posição, se você o executar com os argumentos corretos. O script é uma versão editada de este , mas agora preparado para colocar janelas na área de trabalho virtual em>.

1. Entendendo viewports e coordenadas de janela

Espaços de trabalho na unidade

No Unity, ao contrário de outros gerenciadores de janelas, você tem apenas um espaço de trabalho de abrangência, que é dividido em viewports. No seu caso, sua área de trabalho é dividida em oito viewports.

Como a posição das janelas é definida

A posição da janela, como a saída do comando:

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

é descrito como a posição relativa ao canto superior esquerdo da janela de visualização atual :


Então, se você está na viewport 1 :
uma janela na janela de visualização 2 pode ser posicionada em, e. 1700 (x-wise) x 500 (y-wise)
(minha tela é 1680x1050)


Noentanto,sevocêestivernaviewport6:
amesmajanelaseriaposicionadaem20(x),-550(y)


O uso correto dessas coordenadas é importante para executar o script com os argumentos corretos, conforme descrito abaixo:

2. Como usar o script

O script abaixo pode ser usado para colocar uma nova janela de uma aplicação em sua área de trabalho virtual (abrangendo).

  1. Certifique-se de que wmctrl esteja instalado:

    sudo apt-get install wmctrl
    
  2. Copie o script abaixo em um arquivo vazio, salve-o como setwindow (sem extensão) em ~/bin . Crie o diretório, se ainda não existir. Torne o script executável .

  3. Se você acabou de criar ~/bin , execute o comando source ~/.profile ou efetue logout / in para disponibilizar o diretório em $PATH .
  4. Teste o comando:

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

    por exemplo,

    setwindow gedit 100 100 200 200
    

    Uma janela do gedit deve aparecer na viewport atual.

Notas:

  • Lembre-se de que nem todos os aplicativos permitem tamanhos de janela abaixo de uma determinada largura ou altura. A largura mínima de uma janela gedit no meu sistema é, por exemplo, appr. 470 px.
  • O script só funciona bem se a janela todo couber na janela de exibição de destino, escolha suas coordenadas / tamanhos de acordo. Lembre-se também que o Unity Launcher e o painel usam algum espaço (!) Que pode influenciar a posição da janela.
  • Use <x_position> negativo para colocar janelas à esquerda da (s) janela (s) de visualização atual (s)
  • Use <y_position> negativo para colocar as janelas acima da (s) janela (s) de visualização atual
  • Para abrir novas janelas em diferentes viewports de uma só vez, você pode simplesmente encadear comandos. Observando a configuração da viewport no exemplo "Long story", se eu estiver na viewport 1, posso abrir as janelas do gedit na viewport 1, 2, 3 e 4 com o comando:

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

O script

#!/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


EDIT: a versão preguiçosa

Caso você prefira apenas inserir coordenadas e tamanho, simplesmente como se fosse abrir uma janela na viewport atual, e dar a viewport alvo como um argumento (sem ter que calcular nada), então use a versão abaixo ...

Se você configurá-lo como a primeira versão do script, poderá executá-lo com o comando:

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

Um exemplo: para abrir uma janela Google-Chrome posicionada em 20, 20 , tamanho 300x300 , em viewport 5 :

setwindow google-chrome 20 20 300 300 5

A configuração é praticamente igual à primeira versão do script. Note que este script só funciona corretamente se a janela definida (posição / tamanho) couber completamente dentro da viewport desejada.

O script:

#!/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


Abrindo janelas de aplicativos com argumentos

Para finalizar o trabalho, responda sua pergunta completamente:

Se você executar o script como, por exemplo:

setwindow google-chrome 20 20 300 300 5

ele abrirá uma janela padrão nos desktops visados.
Com a versão mais recente do script, no entanto, você pode adicionar um argumento adicional para abrir a janela do aplicativo, por exemplo, um url :

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

por exemplo:

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

Se o argumento (extra) contiver espaços, use aspas. O exemplo acima abrirá uma janela google-chrome na viewport 3, abrindo o url http://askubuntu.com .

Você pode encadear comandos para abrir várias janelas / URLs em diferentes áreas de trabalho em um comando, por exemplo:

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"
    
por Jacob Vlijm 10.05.2015 / 11:03
1

Isso expande a grande resposta do @Jacob Vlijim acima com um script setwindow ligeiramente modificado:

#!/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)

Uma descrição das alterações:

  1. python3 to python (apenas uma preferência pessoal)
  2. sys.argv to argparse para uma interface de linha de comando melhor
  3. janela de identificação estrita (e não id de processo) parsing da janela
    • alguns programas usam um único ID de processo para várias janelas
  4. while loop 0,5 segundo a 1 segundo de tempo completo
  5. mais nomes de variáveis verbosas / legíveis e adesão pep8
  6. variáveis constantes globais para tamanho de tela em vez de xrandr de confiança

NOTA: Esta é apenas uma versão ligeiramente melhorada que escrevi para uso pessoal no Debian Jessie LXDE. Seus resultados podem variar.

    
por lscstu22 19.12.2016 / 18:29
0

Para os interessados, eu implementei o Desktopen: github.com/snitko/desktopen

Ele permite que você escreva um script para abrir janelas em diferentes viewports e exibe de uma maneira muito amigável.

    
por snitko 02.06.2016 / 03:55