¿Cómo mostrar (subir) todas las ventanas de una aplicación?


21

Tengo una aplicación que usa varias ventanas. ¿Cómo puedo poner rápidamente en primer plano todas las ventanas de esa aplicación?

Cuando me desplazo por las aplicaciones con la rueda de desplazamiento, solo se muestra una ventana. Al ir a la siguiente ventana, la última ventana vuelve al fondo.

Cuando hago clic en el icono de la aplicación, obtengo una visión general de pantalla completa de todas las ventanas. Tengo que seleccionar cada ventana manualmente y mover el mouse por la mitad de la pantalla varias veces.

Mi mejor solución hasta ahora es minimizar todas las ventanas ( Ctrl+ Super+ D) y luego mostrar las ventanas de mi aplicación usando la rueda de desplazamiento.

¿Hay una mejor solución?


@Joschua Traer todas las ventanas de una aplicación al frente no es demasiado difícil, pero ¿cómo le gustaría definir la aplicación? Qué haría una combinación de teclas + hacer clic en la ventana de una aplicación?
Jacob Vlijm

@Joschua o mayby ​​más elegante, ¿una combinación de teclas + 1er carácter del nombre de la aplicación?
Jacob Vlijm

Creo que el comportamiento es el mismo con todas las aplicaciones. La mayoría de las veces extraño esta característica con ventanas de terminal, donde a menudo tengo dos o más ventanas abiertas una al lado de la otra. Luego cambio a una ventana de pantalla completa (por ejemplo, Firefox) y cuando quiero volver a las dos ventanas de terminal es un poco difícil. La mejor manera que encontré hasta ahora es hacer clic con el botón central del mouse en la barra de aplicaciones de Firefox, lo que lleva a Firefox a un segundo plano para que vuelva a tener los dos terminales al frente. Sin embargo, esto solo funciona bien, cuando no hay demasiadas aplicaciones en la parte superior: D
peq

también @Joschua Sería posible tener una combinación de teclas para llevar al frente los grupos de ventanas de aplicaciones ; presione una vez -> se muestran todas las ventanas de Firefox, pres nuevamente -> todas las ventanas de terminal se muestran, etc. interesante. trabajando en ello. aunque tomará un poco de trabajo.
Jacob Vlijm

@JacobVlijm Suena como la dirección correcta .. :) Lo que me parece más importante, es que una combinación de teclas más hacer clic en el ícono trae todas las ventanas de esa aplicación (por ejemplo, muchas terminales como se mencionó anteriormente), preferiblemente extendidas fuera, para que no se superpongan ... (¡Tal vez, algo como esto podría convertirse en parte de Unity ?!)
Joschua

Respuestas:


21

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:

ingrese la descripción de la imagen aquí

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.

    ingrese la descripción de la imagen aquí

  • 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 wmctrlsi 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 ~/binestá 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) ~/biny 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, zenityaparecerá 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-terminalventanas en la ventana gráfica actual:

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

Cómo utilizar:

  • Realice la configuración como se describe en "Cómo usar"
  • Pruébalo con el comando:

    raise_app
    
  • Si todo funciona bien, agréguelo a la combinación de teclas de acceso directo que elija: Elija: Configuración del sistema> "Teclado"> "Accesos directos"> "Accesos directos personalizados". Haga clic en "+" y agregue el comando

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:

ingrese la descripción de la imagen aquí

Presiono una vez Alt+ 1, todas las nautilusventanas aparecen:

<imagen>

Presiono de nuevo Alt+ 1, todas las firefoxventanas aparecen:

<imagen>

Presiono nuevamente Alt+ 1, todas las gnome-terminalventanas vuelven a aparecer, el ciclo comienza de nuevo:

<imagen>

Cómo utilizar

  • Realice la configuración como se describe en "Cómo usar"
  • Agréguelo a la combinación de teclas de acceso directo que elija: Elija: Configuración del sistema> "Teclado"> "Atajos"> "Atajos personalizados". Haga clic en "+" y agregue el comando

    raise_app
    

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 nautilusventanas enterradas debajo de otras ventanas.

<imagen>

Para abrir todas las ventanas de nautilus (ejemplo de acceso directo: Alt+ 1):

  • Presione Alt+ 1, suelte (!)
  • En 3 segundos, ya sea:

    haga clic en el icono de la aplicación en el iniciador

    <imagen>

    o:

    haga clic en una de las ventanas de la aplicación

    <imagen>

    resultado:

    <imagen>


Cómo utilizar:

  • Realice la configuración como se describe en "Cómo usar"
  • Pruébalo con el comando:

    raise_app
    
  • Si todo funciona bien, agréguelo a la combinación de teclas de acceso directo que elija: Elija: Configuración del sistema> "Teclado"> "Accesos directos"> "Accesos directos personalizados". Haga clic en "+" y agregue el comando

Luego:

  • Presione su combinación de teclas y dentro de 3 segundos, ya sea:

    • haga clic en el icono de la aplicación en el iniciador
    • haga clic en una de las ventanas de la aplicación

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 zenityventana, enumerando todas las aplicaciones y el número de sus ventanas en la ventana gráfica actual:

ingrese la descripción de la imagen aquí

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:

  • Realice la configuración como se describe en "Cómo usar"
  • Pruébalo con el comando:

    raise_app
    
  • Si todo funciona bien, agréguelo a la combinación de teclas de acceso directo que elija: Elija: Configuración del sistema> "Teclado"> "Accesos directos"> "Accesos directos personalizados". Haga clic en "+" y agregue el comando

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.

ingrese la descripción de la imagen aquí

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 .desktoparchivo

  1. Prepare la configuración como en "Cómo usar", guarde el primer script (principal) como raise_appen~/bin
  2. Guarde el icono a continuación (haga clic derecho, guardar como) como raise.png

    <icon>

  3. Copie el .desktoparchivo 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.desktopen~/.local/share/applications

  4. Arrastre el .desktoparchivo al iniciador para agregarlo

  5. copie el segundo script, péguelo en un archivo vacío, guárdelo como update_appsen ~/bin, hágalo ejecutable.
  6. Agregue el siguiente comando a sus aplicaciones de inicio (Tablero> Aplicaciones de inicio> Agregar):

    update_apps
    
  7. 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 wmctrlpara crear una lista de ventanas, usando el wmctrl -lpGcomando. 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 forbucle con el comando wmctrl -ia.

En la opción 3,
el script inicia un ciclo de "espera" de 3 segundos, usando el xprop -rootcomando 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.


Estoy de acuerdo, y gracias de nuevo por todo su esfuerzo! :) || Hay algo extraño que no noté antes. A veces, después de usar el Option 2script, cuando una ventana de la aplicación está enfocada (que no está maximizada) y hago clic en otra ventana que está visible "debajo", la aplicación a continuación no obtiene el foco.
Joschua

@Joschua el OP de esta pregunta: askubuntu.com/questions/575830/… me atendió de un error que se introdujo en la última actualización de "características". Verdadero / Falso se mezclaron, causando que el script se bloquee cuando ninguna aplicación tiene más de una ventana. Si usa la opción 2, actualice a la última versión.
Jacob Vlijm

La opción 1 no funciona para mí en ubuntu xenial. something @ something: ~ / bin $ ./raise_app Mensaje Gtk: GtkDialog asignado sin un padre transitorio. Esto es desalentado. Estaba tratando de abrir ventanas de terminal. No pasó nada.
xtrinch

@Nirri, ¿qué nombre de aplicación usaste? El mensaje es bastante normal si se ejecuta una ventana zenity sin un padre Gtk. "Desanimado" no es un error.
Jacob Vlijm

Primeros caracteres de terminal. Funciona, más o menos, abre una ventana de cualquier aplicación, pero solo una de ellas, no todas como se esperaba @ user72216
xtrinch

1

Hay un acceso directo Super+ Wque mostrará la exposición de todas las ventanas abiertas actualmente, aunque eso incluirá otras aplicaciones. Esto viene de forma predeterminada y no requiere ningún cambio, por lo que quizás sea una opción más simple disponible.

Entre otras cosas, puede colocar ventanas en las mitades derecha e izquierda de la pantalla con los botones Ctrl+ Super+ Left/ Right, y cambiar entre ellas con Alt + ~ (tilde, la que está al lado de la tecla número uno).


Sin embargo, eso no lleva todas las ventanas de una aplicación a la cima. Puede verlos, pero no puede usarlos sin tener que hacer clic mucho.
Joschua

1

Si presiona Alt + Tabulador para recorrer las aplicaciones, y llega a una con múltiples ventanas, simplemente mantenga presionada la tecla alt y después de aproximadamente 1 segundo completo, el icono se reemplazará con una vista de todas las ventanas para esa aplicación.

Eso puede o no ser lo que estás buscando, pero funciona para mí y es mucho más simple, ¡así que pensé que compartiría la opción!


1
También puede presionar la tecla de flecha hacia abajo para que las ventanas de la aplicación se muestren de inmediato.
Kris

1

Tomé el script raise_apps.py de @ JacobVlijm e hice algunas mejoras, incluso para hacerlo más robusto.

Específicamente, descubrí que después de un día o dos, el script de @ JacobVlijm dejaría de funcionar y tendría que reiniciarlo manualmente para que volviera a funcionar. En retrospectiva, mi mejor conjetura es que las numerosas llamadas a xrandr eventualmente causan problemas.

De todos modos, adapté su código, aumenté la frecuencia de sondeo de 5 segundos a cada 1 segundo, ya que de todos modos no usa mucha CPU y lo hice más robusto. Por lo general, puedo tenerlo funcionando durante días / semanas sin problemas.

Una advertencia es que solo llamo xrandr una vez durante el inicio, para obtener dimensiones de resolución de pantalla. Entonces, si cambia la resolución de su pantalla (por ejemplo, de 1920x1080 a alguna otra resolución), probablemente quiera reiniciar manualmente raise-apps.py para que recoja la nueva resolución. Personalmente, nunca cambio la resolución de mi pantalla, así que esto no es un problema para mí. Además, tengo buenas razones para creer que demasiadas llamadas a xrandr fueron lo que estaba causando que la versión de @ JacobVlijm del script dejara de funcionar después de un día o dos, por lo que recomendaría encarecidamente no simplemente volver a colocar las numerosas llamadas a xrandr.

Por cierto, debe colocar la imagen raise.png en el directorio / usr / local / icons /. O si desea colocar raise.png en un directorio diferente, realice el cambio apropiado en el script para que el script pueda encontrar el archivo de imagen.

Con suerte, Ubuntu integrará este tipo de funcionalidad 'elevar todas las ventanas' en su sistema lo antes posible, ya que es muy útil:

#!/usr/bin/python2
#
# Note to self:
# You need to add raise.png to /usr/local/icons/ directory.
#
# This script was taken from: /ubuntu/446521/how-to-show-raise-all-windows-of-an-application, 
# (@JacobVlijm's answer), and then improved to fix some
# issues, that were causing it to stop working after a day or two.
#
#
from __future__ import print_function

from sys import stderr, exit
import signal
import gi

gi.require_version('Gtk', '3.0')
gi.require_version('AppIndicator3', '0.1')
from gi.repository import Gtk, AppIndicator3, GObject, GLib

import logging
import logging.handlers

import time
import os
import subprocess
import getpass

logger = logging.getLogger('MyLogger')
logger.setLevel(logging.DEBUG)

log_handler = logging.handlers.SysLogHandler(address='/dev/log')

logger.addHandler(log_handler)


currpath = os.path.dirname(os.path.realpath(__file__))

class Indicator():
    def __init__(self):
        self.app = 'raise-apps'
        iconpath = '/usr/local/icons/raise.png'
        self.indicator = AppIndicator3.Indicator.new(
            self.app, iconpath,
            AppIndicator3.IndicatorCategory.OTHER)
        self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)

        self.prev_menu_item_names = []
        self.menu_items = []

        res_output = get("xrandr").split()
        if (len(res_output) == 0):
            logger.error("raise-apps.py: invocation of xrandr failed! Unable to continue..")
            exit(-1)

        idf = res_output.index("current")
        res = (int(res_output[idf+1]), int(res_output[idf+3].replace(",", "")))
        (self.screen_width, self.screen_height) = res
        logger.info("raise-apps.py: screen resolution is %s x %s" % (self.screen_width, self.screen_height))

        self.indicator.set_menu(self.create_menu())

        GLib.timeout_add_seconds(1.0, self.check_recent)

    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)

        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_items[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_items:

            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):
        # 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]) < self.screen_width and 0 < int(w[4]) < self.screen_height]
        # 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):
        # print("in check_recent()", file=stderr)
        self.menu_items = self.get_apps()
        for app in self.menu_items:
            app[0] = "gnome-terminal" if "gnome-terminal" in app[0] else app[0]
        # check if menu items have changed:
        has_changed = len(self.menu_items) != len(self.prev_menu_item_names)
        if (not has_changed):
            for i in range(len(self.menu_items)):
                if self.prev_menu_item_names[i] != self.menu_items[i][0]:
                    has_changed = True
                    break

        if has_changed:
            GObject.idle_add(
                self.set_new,
                priority=GObject.PRIORITY_DEFAULT)

            self.prev_menu_item_names = []
            for item in self.menu_items:
                self.prev_menu_item_names.append(item[0])

        GLib.timeout_add_seconds(1.0, self.check_recent)


    def stop(self, source):
        Gtk.main_quit()


    def recreate_menu(self, *args):
        logger.info("in recreate_menu()")
        self.prev_menu_item_names = []
        self.menu_items = []

        self.menu_items = self.get_apps()
        for app in self.menu_items:
            app[0] = "gnome-terminal" if "gnome-terminal" in app[0] else app[0]

        GObject.idle_add(
            self.set_new,
            priority=GObject.PRIORITY_DEFAULT)

        self.prev_menu_item_names = []
        for item in self.menu_items:
            self.prev_menu_item_names.append(item[0])


def get(command):
    # enable to get a feel for what this app is doing..
    # print("get", command, file=stderr)
    try:
        return subprocess.check_output(command).decode("utf-8")

    except subprocess.CalledProcessError as e:
        logger.error("raise-apps.py error: cmd=%s, error=%s" % (command, e))
        return ""

    except OSError as e:
        logger.error("raise-apps.py error: cmd=%s, error=%s" % (command, e))
        return ""

def execute(command):
    # enable to get a feel for what this app is doing..
    # print("exec", command, file=stderr)
    try:
        subprocess.call(command)

    except subprocess.CalledProcessError as e:
        logger.error("raise-apps.py error: cmd=%s, error=%s" % (command, e))
        return ""
    except OSError as e:
        logger.error("raise-apps.py error: cmd=%s, error=%s" % (command, e))
    return ""


logger.info("(raise-apps.py is starting up..)")
Indicator()
signal.signal(signal.SIGINT, signal.SIG_DFL)
Gtk.main()
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.