Introdução
O script a seguir permite selecionar duas janelas e, enquanto as duas estiverem abertas, ele aumentará as duas janelas quando o usuário focalizar uma delas. Por exemplo, se alguém vincula as viúvas A e B, passar para A ou B fará com que ambos se elevem acima das outras viúvas.
Para interromper o script, você pode usar killall link_windows.py
no terminal ou fechar e reabrir uma das janelas. Você também pode cancelar a execução pressionando o botão Fechar Xem qualquer uma das caixas de diálogo pop-up de seleção de janela.
Potenciais ajustes:
- várias instâncias do script podem ser usadas para agrupar pares de duas janelas. Por exemplo, se tivermos as janelas A, B, C e D, podemos vincular A e B juntos e C e D juntos.
- várias janelas podem ser agrupadas em uma única janela. Por exemplo, se eu vincular a janela B a A, C a A e D a A, isso significa que, se eu sempre alternar para A, posso levantar todas as 4 janelas ao mesmo tempo.
Uso
Execute o script como:
python link_windows.py
O script é compatível com o Python 3, portanto, também pode ser executado como
python3 link_windows.py
Existem duas opções de linha de comando:
--quiet
ou -q
, permite silenciar as janelas da GUI. Com esta opção, você pode simplesmente clicar com o mouse em duas janelas, e o script começará a vinculá-las.
--help
ou -h
, imprime as informações de uso e descrição.
A -h
opção produz as seguintes informações:
$ 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.
Informações técnicas adicionais podem ser visualizadas via pydoc ./link_windows.py
, onde ./
significa que você deve estar no mesmo diretório que o script.
Processo de uso simples para duas janelas:
Um pop-up aparecerá pedindo para você selecionar uma janela nº 1, pressionar OKou pressionar Enter. O ponteiro do mouse se transformará em uma cruz. Clique em uma das janelas que você deseja vincular.
Um segundo pop-up será exibido, solicitando que você selecione a janela nº 2, pressione OKou aperte Enter. Novamente, o ponteiro do mouse se transformará em uma cruz. Clique na outra janela que você deseja vincular. Depois que a execução começará.
Sempre que você focalizar uma das janelas, o script aumentará a outra janela, mas retornará o foco para a selecionada originalmente (observe - com um atraso de um quarto de segundo para obter o melhor desempenho), criando a sensação de que as janelas estão ligadas.
Se você selecionar a mesma janela as duas vezes, o script será encerrado. Se a qualquer momento você clicar no botão Fechar da caixa de diálogo pop-up, o script será encerrado.
Origem do script
Também disponível como 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()
Notas:
- Ao executar a partir da linha de comando, as caixas de diálogo pop-up produzem a seguinte mensagem:
Gtk-Message: GtkDialog mapped without a transient parent. This is discouraged.
Elas podem ser ignoradas.
- Consulte Como editar / criar novos itens do iniciador no Unity manualmente? para criar um iniciador ou atalho na área de trabalho para esse script, se você deseja iniciá-lo com um clique duplo
- Para vincular esse script a um atalho de teclado para facilitar o acesso, consulte Como adicionar atalhos de teclado?