Inicie o aplicativo somente se ainda não estiver aberto

14

Eu gostaria de imitar o uso do Alfred no Mac OS X, onde se você tentar abrir um aplicativo depois de pesquisá-lo, ele só abrirá uma nova janela se o programa ainda não estiver em execução; concentre-se na instância atualmente em execução desse aplicativo. Existe alguma maneira de alterar o comportamento padrão do lançador para verificar isso antes de abrir uma nova janela?

    
por Dan Jenson 28.03.2014 / 04:35

3 respostas

6

Atualização 7 de abril: Uma versão diferente adicionou e encontrou o Albert, veja a atualização e o bônus abaixo !!!

Com relação à funcionalidade do traço : Você pediu " Existe alguma maneira de alterar o comportamento padrão do lançador para verificar isso antes de abrir uma nova janela ". Resposta básica é, não, como um usuário comum você não tem como adicionar esse comportamento ao traço. No entanto, se houver um desenvolvedor de escopo de unidade que esteja disposto a implementá-lo, você poderá abordá-lo ou desenvolvê-lo por conta própria se tiver determinação e disposição para aprender. Minhas habilidades de codificação são muito modestas, por isso uso shell script e o front-end gráfico disponível para os scripts como uma solução alternativa.

Informações relacionadas

postagem original:

Eu escrevi um script que usa o diálogo do zenity e o wmctrl para obter o que você pediu. Observe que este é um script gráfico, o que significa que ele só funcionará com o Windows, na GUI, e não funcionará se você tentar iniciar algo no tty. Além disso, pelo que entendi, Alfredo faz exatamente a mesma coisa. Você pode criar um atalho na área de trabalho para ele ou atalho do iniciador para ele, conforme descrito aqui e aqui .

O script:

#!/bin/bash
# Author: Serg Kolo
# Description: A launcher script that checks whether
#       or not a window of a particular program already exists
#       If a window of such program is open, bring it to focus
#       Otherwise - launch a new window
#       Written for https://askubuntu.com/q/440142/295286
# Date: April 6 , 2015
#


MYPROG=$( zenity --entry --title='MY LAUNCHER' --text='Type the name of application to run' )
sleep 0.5
wmctrl -lx | awk '{print $3}' | grep -i "$MYPROG"

if [ $? -eq 0 ]; then
    sleep 1         
    wmctrl -xa $MYPROG
   #as an alternative try the line bellow
   #wmctrl -a $MYPROG
    exit 1
else 
    $MYPROG &
    exit 0
fi

Notas laterais: na versão anterior, o script usava echo $ ?, para testar se as expressões anteriores foram bem-sucedidas. De acordo com a sugestão de Muru (da edição), eu mudei o código para uma versão um pouco mais compacta, então sugiro que você dê uma olhada na versão anterior e na atual.

Além disso, anteriormente, wmctrl -a $MYPROG não funcionava com o teste google-chrome ou chromium-browser; por algum motivo estúpido, alguns programas têm a propriedade WM_CLASS da janela em maiúscula, enquanto o programa listado por dpkg --get-selections é minúsculo (apenas leia man wmctrl e execute wmctrl -lx , você saberá). Adicionando que -ax deve cuidar disso. O script exibe a janela do cromo já aberta como deveria

Outra coisa - o wmctlr é um pouco estranho pois precisa de um atraso às vezes (tinha experiência com ele em outro script), então eu tive que adicionar sleep 1 line. Anteriormente, seria uma espécie de dentro e fora do firefox, mas agora funciona de forma dinâmica.

O script em ação

Na animação abaixo você pode ver que na primeira execução do script, há uma instância do firefox aberta, e o script muda o foco para essa janela; No segundo teste, abro uma nova instância do google-chrome, que não foi aberta anteriormente. (Nota: Se você é curioso sobre a área de trabalho, a propósito, isso é openbox com o dock do Cairo)

Por sugestão nos comentários, animação incorporada removida, apenas link postado. Relate se está quebrado por favor! link

Atualização, 7 de abril

Eu melhorei o script um pouco para tornar todos os programas listados na caixa de entrada suspensa do zenity. Agora o usuário não precisa memorizar cada programa, mas pode simplesmente rolar uma lista deles usando as teclas de seta ou apenas abrir o menu suspenso. Além disso, essa versão aprimorada gera janelas não pelo nome, mas pelo ID da janela, o que proporciona um desempenho muito melhor. Note que o modo como eu passo pelos arquivos .desktop é meio redundante, usando o comando cut duas vezes, mas como o script-fu não é tão bom até agora, isso é tudo que posso fazer. Sugestões para melhoria são bem vindas!

#!/bin/bash
# Author: Serg Kolo
# Description: Second version of a launcher script that checks whether
#       or not a window of a particular program already exists
#       If a window of such program is open, bring it to focus
#       Otherwise - launch a new window
#       Written for https://askubuntu.com/q/440142/295286
# Date: April 7 , 2015
#

set -x

MYPROG=$(zenity --entry --text 'Select program from list' --entry-text $(ls /usr/share/applications/*.desktop | cut -d'/' -f5 | cut -d'.' -f1 | xargs echo))
sleep 0.5
# Do we have a window of such program ?
wmctrl -lx| awk '{print $3}'  | grep -i $MYPROG

if [ $? -eq 0 ]; then
    sleep 0.5 # if yes, find that window id, and raise it
    WINID=$(wmctrl -lx | grep -i $MYPROG | awk 'NR==1{print $1}')
    wmctrl -ia $WINID &
 #  exit 0  
else
    echo $MYPROG | grep -i libreoffice
    if [ $? -eq 0  ]
    then
        MYPROG=$(echo $MYPROG | sed 's/-/ --/g')
    fi
    $MYPROG &

#  exit 0 
fi

Bônus:

Naverdade,encontrei Albert , que é a versão para Linux do Alfred, mas não tentei isso sozinho. Vale a pena conferir embora. No entanto, como Jacob observou, ainda é um buggy.

Existe um aplicativo chamado Gnome-Do, que parece graficamente semelhante ao Alfred, no entanto, ele não tem a mesma funcionalidade que este script.

Deixe-me saber se você gosta deste roteiro, se há algo que precisa ser consertado, e não se esqueça de revalorizar a resposta se achar útil

    
por Sergiy Kolodyazhnyy 06.04.2015 / 22:01
4

1. Traço o segundo

Abaixo de um script que pode ser usado como uma alternativa ao Dash, quando se trata de executar aplicativos conforme descrito na sua pergunta.

Existe uma janela com a mesma funcionalidade que o Dash; se digitar um ou mais caracteres do aplicativo, o aplicativo aparecerá na lista. Pressione Enter para iniciar ou elevar o aplicativo, dependendo se ele já está sendo executado ou não.

Você pode chamá-lo de uma combinação de teclas de atalho ou definir um ícone no iniciador para usá-lo de maneira semelhante ao Dash (veja mais abaixo) ou ambos.

Oscript

#!/usr/bin/env python3 import subprocess import os import getpass import time user = getpass.getuser() get = lambda x: subprocess.check_output(["/bin/bash", "-c", x]).decode("utf-8") skip = ["%F", "%U", "%f", "%u"]; trim = ["chrome", "chromium", "nautilus"] def apply(command): if "libreoffice" in command: proc = [l.split()[0] for l in get("ps -u "+user).splitlines() if "soffice.bin" in l] module = command.split("--")[-1] time.sleep(0.1) try: ws = sum([[w.split()[0] for w in get("wmctrl -lp").splitlines() if process in w and module in w.lower()] for process in proc], [])[0] subprocess.call(["wmctrl", "-ia", ws]) except IndexError: subprocess.Popen(["/bin/bash", "-c", command+"&"]) else: check = command.split("/")[-1][:14] proc = [p.split()[0] for p in get("ps -u "+user).splitlines() if check in p] time.sleep(0.5) try: ws = sum([[w.split()[0] for w in get("wmctrl -lp").splitlines() if process in w] for process in proc], []) if command == "nautilus": real_window = [w for w in ws if "_NET_WM_WINDOW_TYPE_NORMAL" in get("xprop -id "+w)][0] else: real_window = ws[0] subprocess.call(["wmctrl", "-ia", real_window]) except IndexError: subprocess.Popen(["/bin/bash", "-c", command+"&"]) # default directories of .desktop files; globally, locally, LibreOffice- specific when separately installed globally = "/usr/share/applications"; locally = os.environ["HOME"]+"/.local/share/applications"; lo_dir = "/opt/libreoffice4.4/share/xdg" # create list of .desktop files; local ones have preference local_files = [it for it in os.listdir(locally) if it.endswith(".desktop")] global_files = [it for it in os.listdir(globally) if it.endswith(".desktop")] lo_spec = [it for it in os.listdir(lo_dir) if it.endswith(".desktop")] if os.path.exists(lo_dir) else [] for f in [f for f in local_files if f in global_files]: global_files.remove(f) for f in [f for f in local_files if f in lo_spec]: lo_spec.remove(f) dtfiles = [globally+"/"+f for f in global_files]+[locally+"/"+f for f in local_files]+[lo_dir+"/"+f for f in lo_spec] # create list of application names / commands valid = [] for f in dtfiles: content = open(f).read() if all(["NoDisplay=true" not in content,"Exec=" in content]): lines = content.splitlines() name = [l.replace("Name=", "") for l in lines if "Name=" in l][0] command = [l.replace("Exec=", "") for l in lines if all(["Exec=" in l, not "TryExec=" in l])][0] valid.append((name, command)) valid.sort(key=lambda x: x[0]) # create zenity list + window list_items = '"'+'" "'.join([f[0] for f in valid])+'"' proposed = 'zenity --list --text "Type one or more characters... " --column="Application List" '+\ '--title="Dash the Second" --height 450 --width 300 '+list_items try: choice = subprocess.check_output(["/bin/bash", "-c", proposed]).decode("utf-8").strip().split("|")[0] command = [r[1] for r in valid if r[0] == choice][0] # command fixes: for s in skip: command = command.replace(" "+s, "") for t in trim: if t in command: command = t apply(command) except subprocess.CalledProcessError: pass

Como usar

O script precisa de wmctrl instalado:

sudo apt-get install wmctrl

Então:

  1. Cole o script acima em um arquivo vazio, salve-o como dash_alternative.py
  2. Adicione a uma combinação de teclas de atalho: Escolha: Configurações do sistema > "Teclado" > "Atalhos" > "Atalhos personalizados". Clique no botão "+" e adicione o comando:

    python3 /path/to/dash_alternative.py
    

Explicação

Quando o script é executado, ele lista todos os aplicativos, representados em /usr/share/applications . Ele procura os arquivos .dektop , criando uma lista de todos os nomes de aplicativos (a partir da primeira linha "Name=") e o comando para executar o aplicativo (a partir da primeira linha "Exec=").

Posteriormente, uma lista do Zenity é criada, apresentando todos os aplicativos de maneira ordenada.

Sempre que um aplicativo é selecionado, o script procura na lista de processos em execução se o aplicativo estiver em execução. Nesse caso, a janela correspondente é levantada. Caso contrário, uma nova instância é aberta.

Notas

  1. Para executar o script em 12.04 (desde que a pergunta original foi marcada como 12.04 , simplesmente altere o shebang para #!/usr/bin/env python e execute-o pelo comando

    python /path/to/dash_alternative.py
    
  2. Tanto quanto eu testei, o script funciona bem. Comandos e seus (não) nomes de processos correspondentes (por exemplo, LibreOffice < > soffice.bin ), diferentes tipos de janelas ( nautilus tem vários tipos de janelas diferentes, além de janelas "reais"), vários lances por aplicativo ( Chromium , Google-chrome ) pode causar exceções, que corrigi nos exemplos acima. Se alguém encontrar um problema, por favor mencione.

2. Adicional: configurando-o como uma alternativa para o traço "real" para executar aplicativos

  1. Copie e proteja o script como mencionado acima
  2. Salve o ícone abaixo (clique com o botão direito do mouse > safe as) como dash_alternative.png

  3. Copie o código abaixo em um arquivo vazio, salve-o em ~/.local/share/applications as dash_thesecond.desktop . Defina os caminhos corretos para /path/to/dash_alternative.py (o script) e /path/to/dash_alternative.png (o ícone)

    [Desktop Entry]
    Name=Dash the Second
    Exec=python3 /path/to/dash_alternative.py
    Icon=/path/to/dash_alternative.png
    Type=Application
    Hidden=false
    
  4. Arraste o arquivo .desktop para o iniciador:

por Jacob Vlijm 07.04.2015 / 10:14
0

Para o launcher (o painel vertical no lado esquerdo da tela), este já é o comportamento padrão, pois é a interface de troca de tarefas.

Para o traço (o bit grande que é aberto quando você clica no logotipo do Ubuntu), não há como alterar o comportamento dessa maneira, sem uma modificação presumivelmente significativa no próprio código-fonte.

No entanto, alguns aplicativos já podem fazer isso, pois são projetados para se comportarem dessa maneira. Todos os aplicativos não são e não devem necessariamente ser implementados dessa maneira.

Como outro recurso, se você abrir a janela com Super + W e começar a digitar o nome de uma aplicação, as janelas da aplicação serão as únicas. mostrado.

    
por dobey 07.04.2015 / 23:25