Como mostrar (aumentar) todas as janelas de um aplicativo?


21

Eu tenho um aplicativo usando várias janelas. Como posso trazer rapidamente todas as janelas desse aplicativo para o primeiro plano?

Quando eu percorro os aplicativos com a roda de rolagem, ele mostra apenas uma janela. Ao ir para a próxima janela, a última janela é trazida para segundo plano novamente.

Quando clico no ícone do aplicativo, obtenho uma visão geral da tela inteira de todas as janelas. Eu tenho que selecionar cada janela manualmente e mover o mouse pela metade da tela várias vezes.

Até agora, minha melhor solução é minimizar todas as janelas ( Ctrl+ Super+ D) e mostrar as janelas do meu aplicativo usando a roda de rolagem.

Existe uma solução melhor?


@ Joschua Trazer todas as janelas de um aplicativo para a frente não é muito difícil, mas como você gostaria de definir o aplicativo? seria uma combinação de teclas + clicar na janela de um aplicativo?
Jacob Vlijm

@ Joschua ou mayby ​​mais elegante, uma combinação de teclas + 1º caractere do nome do aplicativo?
Jacob Vlijm 5/15/15

Eu acho que o comportamento não é o mesmo com todos os aplicativos. Na maioria das vezes, sinto falta desse recurso nas janelas do terminal, onde geralmente tenho duas ou mais janelas abertas lado a lado. Então eu mudo para uma janela de tela cheia (por exemplo, Firefox) e quando eu quero voltar para as duas janelas do terminal, é meio difícil. A melhor maneira que encontrei até agora é clicar com o botão do meio do mouse na barra de aplicativos do Firefox, que traz o Firefox para segundo plano, para que eu tenha os dois terminais na frente novamente. No entanto, isso só funciona bem quando não há muitos aplicativos empilhados no topo: D
peq

também @Joschua Seria possível ter uma combinação de teclas para trazer para a frente grupos de janelas de aplicativos ; pressione uma vez -> todas as janelas do firefox aparecem, pres novamente -> todas as janelas do terminal são exibidas etc. podem ser suavizadas. interessante. trabalhando nisso. vai demorar um pouco de trabalho embora.
Jacob Vlijm

@JacobVlijm Parece a direção certa .. :) O que parece mais importante para mim, é que uma combinação de teclas e um clique no ícone traz todas as janelas desse aplicativo (por exemplo, muitos terminais como peq mencionado) para a frente, de preferência espalhados para fora, de modo que eles não se sobrepõem .. (Talvez, algo como isso poderia tornar-se parte da Unidade ?!)
Joschua

Respostas:


21

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:

insira a descrição da imagem aqui

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.

    insira a descrição da imagem aqui

  • 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 wmctrlse 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 ~/binestá 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) ~/bine 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 zenityjanela 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-terminaljanelas na viewport atual:

insira a descrição da imagem aqui

insira a descrição da imagem aqui

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:

insira a descrição da imagem aqui

Pressiono uma vez Alt+ 1, todas as nautilusjanelas são levantadas:

<image>

Pressiono novamente Alt+ 1, todas as firefoxjanelas são levantadas:

<image>

Pressiono novamente Alt+ 1, todas as gnome-terminaljanelas são levantadas novamente, o ciclo recomeça:

<image>

Como usar

  • Faça a configuração conforme descrito em "Como usar"
  • 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

    raise_app
    

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 nautilusjanelas enterradas sob outras janelas.

<image>

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

    <image>

    ou:

    clique em uma das janelas do aplicativo

    <image>

    resultado:

    <image>


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:

  • Pressione a combinação de teclas e em 3 segundos:

    • clique no ícone do aplicativo no iniciador
    • clique em uma das janelas do aplicativo

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 zenityjanela, listando todos os aplicativos e o número de suas janelas na janela atual:

insira a descrição da imagem aqui

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.

insira a descrição da imagem aqui

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

  1. Prepare a configuração como em "Como usar", salve o primeiro script (principal) como raise_appem~/bin
  2. Salve o ícone abaixo (clique com o botão direito do mouse, salve como) como raise.png

    <icon>

  3. Copie o .desktoparquivo 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.desktopem~/.local/share/applications

  4. Arraste o .desktoparquivo para o iniciador para adicioná-lo

  5. copie o segundo script, cole-o em um arquivo vazio, salve-o como update_appsem ~/bin, torne-o executável.
  6. Adicione o seguinte comando aos seus aplicativos de inicialização (Dash> Startup Applications> Add):

    update_apps
    
  7. 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 wmctrlpara criar uma lista de janelas, usando o wmctrl -lpGcomando 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 forloop com o comando wmctrl -ia.

Na opção 3,
o script inicia um loop de "espera" de três segundos, usando o xprop -rootcomando 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.


Concordo e obrigado novamente por todo o seu esforço! :) || Há uma coisa estranha que eu não percebi antes. Às vezes, depois de usar o Option 2script, quando uma janela do aplicativo é focada (que não é maximizada) e clico em outra janela visível "abaixo", o aplicativo abaixo não obtém o foco.
Joschua

@ Joschua, o OP desta pergunta: askubuntu.com/questions/575830/… me acompanhou de um bug que foi introduzido na atualização mais recente do "recurso". Verdadeiro / Falso foram misturados, causando a falha do script quando nenhum aplicativo tiver mais de uma janela. Se você usar a opção 2, atualize para a versão mais recente.
Jacob Vlijm

A opção 1 não está funcionando para mim no ubuntu xenial. algo @ algo: ~ / bin $ ./raise_app Gtk-Message: GtkDialog mapeado sem um pai temporário. Isso é desencorajado. Eu estava tentando abrir janelas do terminal. Nada aconteceu.
xtrinch 17/09/16

@Nirri qual nome do aplicativo você usou? A mensagem é bastante normal se uma janela zenity for executada sem um pai Gtk. "Desencorajado" não é um erro.
Jacob Vlijm

Primeiros caracteres do terminal. Ele funciona - espécie de - levanta uma janela de qualquer aplicativo - mas apenas um deles, não todos eles como esperado @ user72216
xtrinch

1

Super+ Watalho que irá mostrar expo de todas as janelas abertas atualmente, no entanto, que irá incluir outras aplicações. Isso vem por padrão e não requer alterações, portanto, talvez seja uma opção mais simples disponível.

Entre outras coisas, você pode posicionar as janelas nas metades direita e esquerda da tela com os botões Ctrl+ Super+ Left/ Righte alternar entre elas com Alt + ~ (til, o próximo à tecla número um).


Isso não leva todas as janelas de um aplicativo ao topo. Você pode vê-los, mas não pode usá-los sem ter que clicar muito.
Joschua

1

Se você pressionar Alt + Tab para alternar entre aplicativos e chegar a um com várias janelas, mantenha pressionada a tecla alt e, após cerca de 1 segundo, o ícone será substituído pela visualização de todas as janelas desse aplicativo.

Pode ou não ser o que você está procurando, mas funciona para mim e é muito mais simples, então achei que compartilharia a opção!


11
Você também pode pressionar a tecla de seta para baixo para que as janelas do aplicativo apareçam imediatamente.
Kris

1

Peguei o script raise_apps.py do @ JacobVlijm e fiz alguns aprimoramentos, inclusive para torná-lo mais robusto.

Especificamente, eu descobri que depois de um dia ou dois, o script de @ JacobVlijm parava de funcionar e eu precisava reiniciar o script manualmente para fazê-lo funcionar novamente. Em retrospecto, meu melhor palpite é que as inúmeras chamadas para o xrandr acabam causando problemas.

De qualquer forma, adaptei o código dele, aumentou a frequência de pesquisa de 5 segundos para cada 1 segundo, já que ele não usa muita CPU e o tornou mais robusto. Normalmente, posso executá-lo por dias / semanas sem problemas.

Uma ressalva é que eu chamo o xrandr apenas uma vez durante a inicialização, para obter as dimensões da resolução da tela. Portanto, se você alterar a resolução da tela (por exemplo, de 1920x1080 para outra resolução), provavelmente desejará reiniciar manualmente o raise-apps.py para que ela obtenha a nova resolução. Pessoalmente, nunca mudo a resolução da tela, portanto isso não é um problema para mim. Além disso, tenho fortes razões para acreditar que muitas chamadas para xrandr foram o que estava causando a versão do script de @ JacobVlijm para de funcionar depois de um dia ou dois, então eu recomendaria fortemente não simplesmente colocar as inúmeras chamadas para xrandr de volta ..

BTW, você precisa colocar a imagem raise.png no diretório / usr / local / icons /. Ou, se você deseja colocar o raise.png em um diretório diferente, faça a alteração apropriada no script, para que o script possa encontrar o arquivo de imagem.

Felizmente, o Ubuntu integrará esse tipo de funcionalidade 'raise all windows' em seu sistema mais cedo ou mais tarde, pois é muito ú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()
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.