EDIT - nova resposta -
As respostas abaixo são / ainda são totalmente válidas e, portanto, as opções sugeridas. No entanto, a percepção contínua me fez adicionar esta opção para usar o indicador abaixo, que provavelmente é a solução mais elegante.
Como tal, provavelmente deve substituir a opção 5 (usando um arquivo .desktop).
Simplesmente escolha o aplicativo na lista e todas as janelas do aplicativo correspondente (presentes na viewport atual) serão exibidas:
Como usar
de ppa:
sudo add-apt-repository ppa:vlijm/upfront
sudo apt-get update
sudo apt-get install upfront
... ou manualmente:
#!/usr/bin/env python3
import signal
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('AppIndicator3', '0.1')
from gi.repository import Gtk, AppIndicator3, GObject
import time
from threading import Thread
import os
import subprocess
import getpass
currpath = os.path.dirname(os.path.realpath(__file__))
class Indicator():
def __init__(self):
self.app = 'raise_apps'
iconpath = os.path.join(currpath, "raise.png")
self.indicator = AppIndicator3.Indicator.new(
self.app, iconpath,
AppIndicator3.IndicatorCategory.OTHER)
self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)
self.indicator.set_menu(self.create_menu())
# the thread:
self.update = Thread(target=self.check_recent)
# daemonize the thread to make the indicator stopable
self.update.setDaemon(True)
self.update.start()
def create_menu(self):
# creates the (initial) menu
self.menu = Gtk.Menu()
# separator
initial = Gtk.MenuItem("Fetching list...")
menu_sep = Gtk.SeparatorMenuItem()
self.menu.append(initial)
self.menu.append(menu_sep)
# item_quit.show()
self.menu.show_all()
return self.menu
def raise_wins(self, *args):
index = self.menu.get_children().index(self.menu.get_active())
selection = self.menu_items2[index][1]
for w in selection:
execute(["wmctrl", "-ia", w])
def set_new(self):
# update the list, appearing in the menu
for i in self.menu.get_children():
self.menu.remove(i)
for app in self.menu_items2:
sub = Gtk.MenuItem(app[0])
self.menu.append(sub)
sub.connect('activate', self.raise_wins)
# separator
menu_sep = Gtk.SeparatorMenuItem()
self.menu.append(menu_sep)
# quit
item_quit = Gtk.MenuItem('Quit')
item_quit.connect('activate', self.stop)
self.menu.append(item_quit)
self.menu.show_all()
def get_apps(self):
# calculate screen resolution
res_output = get("xrandr").split(); idf = res_output.index("current")
res = (int(res_output[idf+1]), int(res_output[idf+3].replace(",", "")))
# creating window list on current viewport / id's / application names
w_data = [l.split() for l in get(["wmctrl", "-lpG"]).splitlines()]
# windows on current viewport
relevant = [w for w in w_data if 0 < int(w[3]) < res[0] and 0 < int(w[4]) < res[1]]
# pids
pids = [l.split() for l in get(["ps", "-u", getpass.getuser()]).splitlines()]
matches = [[p[-1], [w[0] for w in relevant if w[2] == p[0]]] for p in pids]
return [m for m in matches if m[1]]
def check_recent(self):
self.menu_items1 = []
while True:
time.sleep(4)
self.menu_items2 = self.get_apps()
for app in self.menu_items2:
app[0] = "gnome-terminal" if "gnome-terminal" in app[0] else app[0]
if self.menu_items2 != self.menu_items1:
GObject.idle_add(
self.set_new,
priority=GObject.PRIORITY_DEFAULT
)
self.menu_items1 = self.menu_items2
def stop(self, source):
Gtk.main_quit()
def get(command):
return subprocess.check_output(command).decode("utf-8")
def execute(command):
subprocess.Popen(command)
Indicator()
GObject.threads_init()
signal.signal(signal.SIGINT, signal.SIG_DFL)
Gtk.main()
O indicador precisa wmctrl
sudo apt-get wmctrl
Copie o indicador para um arquivo vazio, salve-o como raise_apps.py
Copie a imagem abaixo, salve-a exatamente com o mesmo nome raise.png
no mesmo diretório que o indicador.
Em seguida, basta executá-lo pelo comando:
python3 /path/to/raise_apps.py
Adicione se você deseja inicializar aplicativos:
/bin/bash -c "sleep 10 && python3 /path/to/raise_apps.py"
RESPOSTA ANTIGA:
Sobre a pergunta
Com as ferramentas certas, não é muito complicado "apenas" aumentar todas as janelas de um aplicativo. É um pouco mais complicado garantir que apenas as janelas da viewport atual sejam levantadas. O verdadeiro desafio, no entanto, é encontrar uma maneira conveniente de disponibilizar a ação ao usuário.
Abaixo de cinco opções para cuidar disso, para mostrar como isso pode ser feito. Todas as opções estão prontas para serem usadas. A última opção, no entanto, é meio experimental; funciona bem, mas possui algumas desvantagens cosméticas menores, conforme explicado na descrição da opção. Eu o adicionei como um conceito .
Espalhar as janelas automaticamente de maneira não sobreposta, como sugerido em um comentário, não me parece uma idéia prática; se você trabalhar em uma configuração de janela agrupada (em termos de aplicativo), o script poderá reorganizar indesejadamente as janelas.
Como usar
Para todas as opções, você precisa:
instale wmctrl
se ainda não estiver no seu sistema:
sudo apt-get install wmctrl
crie, se ainda não existir, o diretório:
~/bin
(explicação: o diretório ~/bin
está em $ PATH, para que você possa executar executáveis pelo nome)
Copie o script, correspondente à opção, cole-o em um arquivo vazio, salve-o como raise_app
(sem extensão) ~/bin
e torne-o executável
Nas opções separadas, possíveis etapas adicionais serão explicadas.
Opção 1: escolha o aplicativo digitando um ou mais caracteres
- Pressione uma combinação de teclas, uma
zenity
janela aparecerá
- Digite um ou mais caracteres do nome do aplicativo na caixa de entrada
- Pressione Enter
Isso fará com que todas as janelas do aplicativo correspondente (na viewport atual ) fiquem à frente.
aumente todas as gnome-terminal
janelas na viewport atual:
Como usar:
- Faça a configuração conforme descrito em "Como usar"
Execute-o de teste pelo comando:
raise_app
Se tudo funcionar bem, adicione-o a uma combinação de teclas de atalho de sua escolha: Escolha: Configurações do sistema> "Teclado"> "Atalhos"> "Atalhos personalizados". Clique no "+" e adicione o comando
O script:
#!/usr/bin/env python3
import subprocess
import getpass
def get(command):
return subprocess.check_output(["/bin/bash", "-c", command]).decode("utf-8")
def execute(command):
subprocess.Popen(["/bin/bash", "-c", command])
# calculate screen resolution
res_output = get("xrandr").split(); idf = res_output.index("current")
res = (int(res_output[idf+1]), int(res_output[idf+3].replace(",", "")))
# creating window list on current viewport / id's / application names
w_data = [l.split()[0:7] for l in get("wmctrl -lpG").splitlines()]
windows = [[get("ps -u "+getpass.getuser()+" | grep "+w[2]).split()[-1], w[0]]
for w in w_data if 0 < int(w[3]) < res[0] and 0 < int(w[4]) < res[1]]
# ask user for first characters
try:
arg = get('zenity --entry --text "first characters" --title "application"').strip()
except subprocess.CalledProcessError:
pass
# raise matching windows
try:
[execute("wmctrl -ia "+item[1]) for item in windows if item[0].startswith(arg)]
except (subprocess.CalledProcessError, NameError):
pass
Opção 2: alterne entre aplicativos e abra suas janelas com uma combinação de teclas:
Digamos que eu tenho o script abaixo em uma combinação de teclas Alt+ 1. Tenho várias janelas abertas de:
- Raposa de fogo
- gnome-terminal
- nautilus
O estado atual:
Pressiono uma vez Alt+ 1, todas as nautilus
janelas são levantadas:
Pressiono novamente Alt+ 1, todas as firefox
janelas são levantadas:
Pressiono novamente Alt+ 1, todas as gnome-terminal
janelas são levantadas novamente, o ciclo recomeça:
Como usar
Em seguida, percorra seus aplicativos com janelas de aplicativos agrupadas com sua combinação de teclas.
O script:
#!/usr/bin/env python3
import subprocess
import getpass
include_single = True # set to False if you only want to cycle through apps with multiple windows
def get(command):
return subprocess.check_output(["/bin/bash", "-c", command]).decode("utf-8")
def execute(command):
subprocess.Popen(["/bin/bash", "-c", command])
def get_frontmost():
cmd = "xprop -root"
frontmost = [l for l in get(cmd).splitlines() if\
"ACTIVE_WINDOW(WINDOW)" in l][0].split()[-1]
return frontmost[:2]+"0"+frontmost[2:]
# calculate screen resolution
res_output = get("xrandr").split(); idf = res_output.index("current")
res = (int(res_output[idf+1]), int(res_output[idf+3].replace(",", "")))
# creating window list on current viewport / id's / application names
w_data = [l.split()[0:7] for l in get("wmctrl -lpG").splitlines()]
windows = [[get("ps -u "+getpass.getuser()+" | grep "+w[2]).split()[-1], w[0]]
for w in w_data if 0 < int(w[3]) < res[0] and 0 < int(w[4]) < res[1]]
# create application list to cycle through
if include_single == False:
pre = [it[0] for it in windows]
apps = sorted(list(set([it for it in pre if pre.count(it) > 1])))
else:
apps = sorted(list(set([it[0] for it in windows])))
if len(apps) == 0:
pass
else:
# get the frontmost window as a last itm in the cycle
front = get_frontmost()
front_pid = [l.split()[2] for l in get("wmctrl -lp").splitlines() if front in l][0]
last_infront = get("ps -u "+getpass.getuser()+" | grep "+front_pid).split()[-1]
# determine next apllication to raise
if not last_infront in apps or last_infront == apps[-1]:
arg = apps[0]
print(arg)
else:
arg = apps[apps.index(last_infront)+1]
# raise matching windows
try:
[execute("wmctrl -ia "+item[1]) for item in windows if item[0] == arg]
except (subprocess.CalledProcessError, NameError):
pass
Opção 3: pressione combinação de teclas + clique no ícone do iniciador - ou - janela do aplicativo para abrir todas as janelas na janela atual
Essa é provavelmente a opção mais próxima do descrito na pergunta / comentário.
Digamos que eu tenha uma área de trabalho bagunçada com três nautilus
janelas enterradas sob outras janelas.
Para aumentar todas as janelas do nautilus (exemplo de atalho: Alt+ 1):
- Pressione Alt+ 1, solte (!)
Dentro de 3 segundos, qualquer um:
clique no ícone do aplicativo no iniciador
ou:
clique em uma das janelas do aplicativo
resultado:
Como usar:
- Faça a configuração conforme descrito em "Como usar"
Execute-o de teste pelo comando:
raise_app
Se tudo funcionar bem, adicione-o a uma combinação de teclas de atalho de sua escolha: Escolha: Configurações do sistema> "Teclado"> "Atalhos"> "Atalhos personalizados". Clique no "+" e adicione o comando
Então:
O script
#!/usr/bin/env python3
import subprocess
import getpass
import time
def get(command):
return subprocess.check_output(["/bin/bash", "-c", command]).decode("utf-8")
def execute(command):
subprocess.Popen(["/bin/bash", "-c", command])
def get_frontmost():
cmd = "xprop -root"
frontmost = [l for l in get(cmd).splitlines() if\
"ACTIVE_WINDOW(WINDOW)" in l][0].split()[-1]
return frontmost[:2]+"0"+frontmost[2:]
# calculate screen resolution
res_output = get("xrandr").split(); idf = res_output.index("current")
res = (int(res_output[idf+1]), int(res_output[idf+3].replace(",", "")))
# get window data for various purposes
w_data = get("wmctrl -lpG").splitlines()
non_windows = sum([[l.split()[0] for l in w_data if it in l]\
for it in ("unity-launcher", "unity-panel", "unity-dash", "Hud")], [])
# get id of current window
curr_window = get_frontmost()
# user gets 3 seconds to pick an application window (or launcher icon)
t = 0
while t < 4:
w_id1 = get_frontmost()
time.sleep(1)
w_id2 = get_frontmost()
if w_id1 == w_id2 or w_id2 in non_windows+[curr_window]:
t = t+1
else:
new_frontmost = w_id2
break
# raise
try:
pid = [l.split()[2] for l in w_data if new_frontmost in l]
wl_data = [l.split() for l in w_data]
raise_windows = [l[0] for l in wl_data if pid[0] == l[2] and\
0 < int(l[3]) < res[0] and 0 < int(l[4]) < res[1]]
[execute("wmctrl -ia "+item) for item in raise_windows]
except NameError:
pass
Opção 4: uma combinação de teclas chama uma lista de opções, mostrando o número de janelas por aplicativo na viewport atual
Este acabou por ser mais conveniente do que eu assumi:
Pressionar a combinação de teclas (novamente exemplo-) Alt+ 1chama uma zenity
janela, listando todos os aplicativos e o número de suas janelas na janela atual:
Simplesmente pressionando as setas ▴ou ▾o levará à opção correta. Pressione Entere todas as janelas do aplicativo escolhido são levantadas.
Como usar:
- Faça a configuração conforme descrito em "Como usar"
Execute-o de teste pelo comando:
raise_app
Se tudo funcionar bem, adicione-o a uma combinação de teclas de atalho de sua escolha: Escolha: Configurações do sistema> "Teclado"> "Atalhos"> "Atalhos personalizados". Clique no "+" e adicione o comando
O script
#!/usr/bin/env python3
import subprocess
import getpass
def get(command):
return subprocess.check_output(["/bin/bash", "-c", command]).decode("utf-8")
def execute(command):
subprocess.Popen(["/bin/bash", "-c", command])
# calculate screen resolution
res_output = get("xrandr").split(); idf = res_output.index("current")
res = (int(res_output[idf+1]), int(res_output[idf+3].replace(",", "")))
# creating window list on current viewport / id's / application names
w_data = [l.split()[0:7] for l in get("wmctrl -lpG").splitlines()]
windows = [[get("ps -u "+getpass.getuser()+" | grep "+w[2]).split()[-1], w[0]]
for w in w_data if 0 < int(w[3]) < res[0] and 0 < int(w[4]) < res[1]]
# preparing zenity optionlist
apps = [item[0] for item in windows]
# prevent multiple zenity windows
if apps.count("zenity") > 1:
pass
elif apps.count("zenity") > 0:
execute('zenity --info --text "Another Zenity window is open already"')
# preventing empty windowlist
elif len(apps) > 0:
applist = [[app, str(apps.count(app))] for app in set(apps)]
applist.sort(key=lambda x: x[1])
# calling zenity window
try:
arg = get('zenity --list --text "Choose an application" '+\
'--title "Current windows" '+\
'--column "application" '+\
'--column "windows" '+\
'--height 250 '+\
'--width 250 '+\
(" ").join(sum(applist, [])))
except subprocess.CalledProcessError:
pass
# raise matching windows
try:
[execute("wmctrl -ia "+item[1]) \
for item in windows if arg.startswith(item[0])]
except (subprocess.CalledProcessError, NameError):
pass
else:
execute('zenity --info --text "No windows to list"')
Opção 5: elevar janelas de aplicativos em execução a partir de um ícone do iniciador
Essa opção existe em um ícone do iniciador, com os aplicativos atualmente em execução em uma lista rápida. Escolha uma e todas as janelas dos aplicativos serão levantadas.
O iniciador é atualizado automaticamente quando a lista de aplicativos em execução (na janela atual) é alterada. A lista rápida mostra uma lista diferente em outras viewports, nas quais janelas de outros aplicativos são abertas (levará de 1 a 2 segundos para se adaptar).
Como mencionado, embora totalmente funcional, essa opção é um conceito . Ele tem algumas pequenas desvantagens cosméticas como é. O mais importante:
- O cursor "roda" continua girando por alguns segundos após uma ação. Embora não afete a funcionalidade, é uma desvantagem estética.
- Demora de 1 a 2 segundos para que a lista de aplicativos no ícone do iniciador seja atualizada após a alteração da lista de aplicativos em execução.
Além disso, a configuração é um pouco mais complicada (embora explicada em detalhes abaixo):
Como usar
Abaixo você encontrará:
dois scripts / um ícone / um .desktop
arquivo
- Prepare a configuração como em "Como usar", salve o primeiro script (principal) como
raise_app
em~/bin
Salve o ícone abaixo (clique com o botão direito do mouse, salve como) como raise.png
Copie o .desktop
arquivo para um arquivo vazio, edite a linha
Icon=/path/to/raise.png
para o caminho real para o ícone (caminhos com espaços entre aspas)
Salve-o como raise.desktop
em~/.local/share/applications
Arraste o .desktop
arquivo para o iniciador para adicioná-lo
- copie o segundo script, cole-o em um arquivo vazio, salve-o como
update_apps
em ~/bin
, torne-o executável.
Adicione o seguinte comando aos seus aplicativos de inicialização (Dash> Startup Applications> Add):
update_apps
- Saia e faça login novamente para fazê-lo funcionar.
O primeiro script
#!/usr/bin/env python3
import subprocess
import getpass
import sys
arg = sys.argv[1]
def get(command):
return subprocess.check_output(["/bin/bash", "-c", command]).decode("utf-8")
def execute(command):
subprocess.Popen(["/bin/bash", "-c", command])
# calculate screen resolution
res_output = get("xrandr").split(); idf = res_output.index("current")
res = (int(res_output[idf+1]), int(res_output[idf+3].replace(",", "")))
# creating window list on current viewport / id's / application names
w_data = [l.split()[0:7] for l in get("wmctrl -lpG").splitlines()]
windows = [[get("ps -u "+getpass.getuser()+" | grep "+w[2]).split()[-1], w[0]]
for w in w_data if 0 < int(w[3]) < res[0] and 0 < int(w[4]) < res[1]]
try:
[execute("wmctrl -ia "+item[1]) for item in windows if item[0].startswith(arg)]
except (subprocess.CalledProcessError, NameError):
pass
O segundo script
#!/usr/bin/env python3
import subprocess
import getpass
import time
import os
dtfile = os.environ["HOME"]+"/.local/share/applications/raise.desktop"
def get(command):
return subprocess.check_output(["/bin/bash", "-c", command]).decode("utf-8")
def execute(command):
subprocess.Popen(["/bin/bash", "-c", command])
# calculate screen resolution
res_output = get("xrandr").split(); idf = res_output.index("current")
res = (int(res_output[idf+1]), int(res_output[idf+3].replace(",", "")))
# creating window list on current viewport / id's / application names
def applist():
try:
w_data = [l.split()[0:7] for l in get("wmctrl -lpG").splitlines()]
windows = [[get("ps -u "+getpass.getuser()+" | grep "+w[2]).split()[-1], w[0]]
for w in w_data if 0 < int(w[3]) < res[0] and 0 < int(w[4]) < res[1]]
except subprocess.CalledProcessError:
return []
else:
return set([app[0] for app in windows])
def update_dtfile(applications, text):
actionline = "Actions="+(";").join(applications)+";\n"
with open(dtfile) as src:
lines = src.readlines()
lines = lines[:[i for i in range(len(lines)) \
if lines[i].startswith("Actions=")][0]]+[actionline]
for item in text:
for it in item:
lines.append(it)
with open(dtfile, "wt") as out:
for line in lines:
out.write(line)
while True:
apps1 = applist()
time.sleep(1)
apps2 = applist()
if apps1 != apps2:
text = [["[Desktop Action "+it+"]\n", "Name="+it+"\n",
"Exec=raise_app "+it+"\n", "OnlyShowIn=Unity;\n\n",
]for it in apps2]
update_dtfile(apps2, text)
O arquivo .desktop
[Desktop Entry]
Name=Raise application windows
Comment=Raise groups of windows
Icon=/path/to/raise.png
Terminal=false
Type=Application
Version=1.0
Actions=
Breve explicação
Todas as soluções acima são usadas wmctrl
para criar uma lista de janelas, usando o wmctrl -lpG
comando Este comando produz linhas, parecidas com:
0x044000b3 0 3429 65 24 1615 1026 jacob-System-Product-Name unity - How to show all windows of an application? - Ask Ubuntu - Mozilla Firefox
Essas linhas incluem:
- 1ª coluna: o ID da janela (que podemos usar para aumentá-lo)
- 3ª coluna: o pid que possui a janela.
- 4ª / 5ª coluna: a geometria da janela xy (que usamos para ver se a janela está na viewport atual, icw
xrandr
)
O pid é pesquisado na saída de ps -u <username>
para obter uma identificação "legível pelo usuário" (nome) do aplicativo.
Assim, podemos alocar janelas para aplicativos. Posteriormente podemos levantar as janelas de um determinado aplicativo em um for
loop com o comando wmctrl -ia
.
Na opção 3,
o script inicia um loop de "espera" de três segundos, usando o xprop -root
comando repetidamente para verificar se há alguma alteração na janela da frente; isso acontecerá se o usuário clicar no ícone do iniciador para abrir a janela de um aplicativo ou clicar diretamente na janela. Nesse caso, o loop while interrompe e pesquisa o "novo" aplicativo mais à frente e, posteriormente, gera todas as outras janelas desse aplicativo.