EDITAR -nueva respuesta-
La (s) respuesta (s) a continuación es / siguen siendo totalmente válidas, por lo que las opciones sugeridas Sin embargo, el conocimiento continuo me hizo agregar esta opción para usar el siguiente indicador, que probablemente sea la solución más elegante.
Como tal, probablemente debería reemplazar la opción 5 (usando un archivo .desktop).
Simplemente elija la aplicación de la lista, y todas las ventanas de la aplicación correspondiente (presente en la ventana gráfica actual) mostrarán:
Cómo utilizar
de ppa:
sudo add-apt-repository ppa:vlijm/upfront
sudo apt-get update
sudo apt-get install upfront
... o 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()
El indicador necesita wmctrl
sudo apt-get wmctrl
Copie el indicador en un archivo vacío, guárdelo como raise_apps.py
Copie la imagen a continuación, guárdela exactamente nombrada raise.png
en el mismo directorio que el indicador.
Luego simplemente ejecútelo con el comando:
python3 /path/to/raise_apps.py
Agregue si desea iniciar aplicaciones:
/bin/bash -c "sleep 10 && python3 /path/to/raise_apps.py"
ANTIGUA RESPUESTA:
Sobre la pregunta
Con las herramientas adecuadas, no es muy complicado "solo" abrir todas las ventanas de una aplicación. Es un poco más complicado asegurarse de que solo se levanten las ventanas de la ventana gráfica actual. Sin embargo, el verdadero desafío es encontrar una manera conveniente de poner la acción a disposición del usuario.
A continuación, cinco opciones para encargarse de eso, para mostrar cómo se puede hacer. Todas las opciones están listas para ser utilizadas. Sin embargo, la última opción es algo experimental; funciona bien pero tiene algunos inconvenientes cosméticos menores, como se explica en la descripción de la opción. Sin embargo, lo agregué como concepto .
Difundir las ventanas automáticamente de forma no superpuesta, como se sugiere en un comentario, no me parece una idea práctica; si trabaja en una configuración de ventana agrupada (en cuanto a la aplicación), el script posiblemente reorganizaría ventanas de forma no deseada.
Cómo utilizar
Para todas las opciones necesita:
instalar wmctrl
si aún no está en su sistema:
sudo apt-get install wmctrl
cree, si aún no existe, el directorio:
~/bin
(explicación: el directorio ~/bin
está en $ PATH, por lo que puede ejecutar ejecutables por su nombre)
Copie el script, correspondiente a la opción, péguelo en un archivo vacío, guárdelo como raise_app
(sin extensión) ~/bin
y hágalo ejecutable
En las opciones separadas, se explicarán los posibles pasos adicionales.
Opción 1: elija la aplicación ingresando uno o más caracteres
- Presione una combinación de teclas,
zenity
aparecerá una ventana
- Ingrese uno o más caracteres del nombre de la aplicación en el cuadro de entrada
- Presione enter
Esto hará que todas las ventanas de la aplicación coincidente (en la ventana gráfica actual ) se muestren al frente.
elevar todas las gnome-terminal
ventanas en la ventana gráfica actual:
Cómo utilizar:
La secuencia de comandos:
#!/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
Opción 2: recorrer las aplicaciones y subir sus ventanas con una combinación de teclas:
Digamos que tengo el script a continuación bajo una combinación de teclas Alt+ 1. Tengo varias ventanas abiertas de:
- Firefox
- terminal de gnomo
- nautilo
El estado actual:
Presiono una vez Alt+ 1, todas las nautilus
ventanas aparecen:
Presiono de nuevo Alt+ 1, todas las firefox
ventanas aparecen:
Presiono nuevamente Alt+ 1, todas las gnome-terminal
ventanas vuelven a aparecer, el ciclo comienza de nuevo:
Cómo utilizar
Luego, recorra sus aplicaciones con ventanas de aplicaciones agrupadas con su combinación de teclas.
La secuencia de comandos:
#!/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
Opción 3: presione la combinación de teclas + haga clic en el icono del iniciador -o-- ventana de la aplicación para abrir todas las ventanas en la ventana gráfica actual
Esta es probablemente la opción más cercana a lo que se describe en la pregunta / comentario.
Digamos que tengo un escritorio desordenado con tres nautilus
ventanas enterradas debajo de otras ventanas.
Para abrir todas las ventanas de nautilus (ejemplo de acceso directo: Alt+ 1):
Cómo utilizar:
Luego:
La secuencia de comandos
#!/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
Opción 4: una combinación de teclas llama a una lista de opciones, que muestra el número de ventanas por aplicación en la ventana gráfica actual
Este resultó ser más conveniente de lo que supuse:
Al presionar la combinación de teclas (nuevamente ejemplo-) Alt+ se 1llama a una zenity
ventana, enumerando todas las aplicaciones y el número de sus ventanas en la ventana gráfica actual:
Simplemente presionando las flechas ▴o ▾le llevará a la opción correcta. Presione Entery se abrirán todas las ventanas de la aplicación elegida.
Cómo utilizar:
La secuencia de comandos
#!/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"')
Opción 5: abrir ventanas de aplicaciones en ejecución desde un icono de iniciador
Esta opción existe de un icono de iniciador, con las aplicaciones que se ejecutan actualmente en una lista rápida. Elija uno y se abrirán todas las ventanas de las aplicaciones.
El iniciador se actualiza automáticamente cuando cambia la lista de aplicaciones en ejecución (en la ventana gráfica actual). La lista rápida muestra una lista diferente en otras ventanas gráficas, donde se abren ventanas de otras aplicaciones (tomará 1-2 segundos para adaptarse).
Como se mencionó, aunque es completamente funcional, esta opción es un concepto . Tiene algunas desventajas cosméticas menores como es. El más importante:
- La "rueda" del cursor sigue girando durante unos segundos después de una acción. Aunque no afecta la funcionalidad, es un inconveniente cosmético.
- La lista de aplicaciones en el icono del iniciador tarda entre 1 y 2 segundos en actualizarse después de que la lista de aplicaciones en ejecución cambie.
Además, la configuración es un poco más complicada (aunque se explica en detalle a continuación):
Cómo utilizar
Abajo encontrarás:
dos scripts / un ícono / un .desktop
archivo
- Prepare la configuración como en "Cómo usar", guarde el primer script (principal) como
raise_app
en~/bin
Guarde el icono a continuación (haga clic derecho, guardar como) como raise.png
Copie el .desktop
archivo en un archivo vacío, edite la línea
Icon=/path/to/raise.png
a la ruta real al icono (rutas con espacios entre comillas)
Guárdelo como raise.desktop
en~/.local/share/applications
Arrastre el .desktop
archivo al iniciador para agregarlo
- copie el segundo script, péguelo en un archivo vacío, guárdelo como
update_apps
en ~/bin
, hágalo ejecutable.
Agregue el siguiente comando a sus aplicaciones de inicio (Tablero> Aplicaciones de inicio> Agregar):
update_apps
- Cierre sesión y vuelva a iniciarla para que funcione.
El primer guion
#!/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
El segundo guión
#!/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)
El archivo .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 explicacion
Todas las soluciones anteriores se usan wmctrl
para crear una lista de ventanas, usando el wmctrl -lpG
comando. Este comando produce líneas, parecidas a:
0x044000b3 0 3429 65 24 1615 1026 jacob-System-Product-Name unity - How to show all windows of an application? - Ask Ubuntu - Mozilla Firefox
Estas líneas incluyen:
- Primera columna: la identificación de la ventana (que podemos usar para elevarla)
- 3ra columna: el pid que posee la ventana.
- 4ta / 5ta columna: la geometría de la ventana xy (que usamos para ver si la ventana está en la ventana gráfica actual, icw
xrandr
)
El pid se busca en la salida de ps -u <username>
para obtener una identificación (nombre) "legible por el usuario" de la aplicación.
Por lo tanto, podemos asignar ventanas a las aplicaciones. Posteriormente podemos elevar las ventanas de una aplicación dada en un for
bucle con el comando wmctrl -ia
.
En la opción 3,
el script inicia un ciclo de "espera" de 3 segundos, usando el xprop -root
comando repetidamente para ver si hay algún cambio en la ventana más cercana; Esto sucederá si el usuario hace clic en el ícono del iniciador para abrir la ventana de una aplicación o hace clic directamente en una ventana. Si es así, el bucle while se rompe y busca la "nueva" aplicación de primer plano, y posteriormente levanta todas las demás ventanas de esa aplicación.