Como posso adicionar uma lista rápida dinâmica e específica de aplicativo para arquivos usados recentemente ao Unity Launcher?

4

Seria um recurso incrível acessar documentos recentemente usados do LibreOffice com uma lista rápida dinâmica no inicializador. Há bastante experiência em como criar personalizado listas rápidas estáticas .

Mas há alguém que possa dar alguma orientação construtiva sobre como criar uma lista rápida dinâmica para documentos usados recentemente?

O wiki do Ubuntu tem uma breve descrição sobre como criar listas rápidas com python ou vala. Não tenho experiência em nenhum dos dois e não encontrei scripts de exemplo abrangentes para listas rápidas dinâmicas por aí. Portanto, estou procurando uma maneira mais fácil de implementá-lo ou alguém que já tenha visto / visto.

    
por joaoal 18.03.2016 / 11:23

1 resposta

4

Adicionando uma seção dinâmica "recentemente usada" ao lançador de um aplicativo

A integração completa de uma aplicação com a lista dinâmica -entries provavelmente precisa ser feita de dentro da aplicação. Afinal, as informações mais diretas sobre os arquivos usados vêm do próprio aplicativo.

No entanto, como a edição do código-fonte está fora do escopo do que estamos fazendo, esse não seria o caminho a seguir.

Então o que?

Isso não significa que não possamos alcançar exatamente o mesmo resultado, talvez até de maneira mais flexível e geral, a partir de "fora". Todas as informações de que precisamos estão disponíveis no arquivo atualizado dinamicamente: ~/.local/share/recently-used.xbel , do qual podemos recuperar o histórico completo de arquivos abertos, a data correspondente & amp; informações de tempo e o aplicativo que foi usado.

Além disso, adicionar uma seção atualizada dinamicamente a um lançador pode muito bem ser feito como parte da seção "tradicional" (estática). A chave da solução é, então, criar um processo que cuide das ações acima, sem adicionar uma carga perceptível ao sistema.
Como mencionado em o link da questão, alguns processo em segundo plano seria necessário de qualquer maneira para acompanhe as alterações e passe as instruções.

O script abaixo está fazendo exatamente isso.

A solução; um script de plano de fundo

Os valores no script abaixo são especificamente definidos para LibreOffice e seus documentos. Sem qualquer edição, ele pode ser usado para adicionar uma seção usada recentemente ao LibreOffice-Writer launcher. Ele mostrará os 10 últimos documentos usados, abertos por qualquer um dos LibreOffice -modules.

A solução pode, no entanto, ser usada para adicionar uma seção "recentemente usada" a muitas aplicações com um arquivo .desktop em /usr/share/applications . Como o arquivo ~/.local/share/recently-used.xbel é Gtk relacionado, provavelmente, os aplicativos com uma janela Gtk serão nossos candidatos em potencial (ou seja, se o aplicativo abrir e editar arquivos). Além disso, o número de arquivos a mostrar é arbitrário.

Como fica

A solução adiciona uma seção ao inicializador de destino no iniciador do Unity, mostrando um número arbitrário de arquivos usados recentemente, por exemplo:

  • mostra os últimos sete arquivos:

  • ou os últimos dez arquivos:

  • Com a mesma facilidade, no entanto, podemos dar ao gedit launcher uma seção dinâmica, mostrando os últimos sete arquivos, abertos com gedit (veja a imagem abaixo)

Como usar

Supondo que você tenha o LibreOffice pré-instalado (a versão baixada não possui um arquivo .desktop referenciando em /usr/share/applications que é necessário pelo script, mas em outro lugar, por favor mencione se você precisa configurar o LO baixado separadamente versão)

  1. Copie o script abaixo em um arquivo vazio, salve-o como dynamic_recent.py Para LibreOffice , o nome do processo é soffice , já definido corretamente no script.

    #!/usr/bin/env python3
    import subprocess
    import os
    import time
    import shutil
    
    # --- set the number of docs to show in recently used
    n = 7
    # --- set the process name of the targeted application
    application = "soffice"
    #--- ONLY change the value below into "xdg-open" if you do not use LO preinstalled
    #    else the value should be the same as in application = (above)
    open_cmd = "soffice"
    # --- set the targeted .desktop file (e.g. "gedit.desktop")
    target = "libreoffice-writer.desktop"
    
    # --- don't change anything below
    home = os.environ["HOME"]+"/.local/share"
    loc = home+"/applications/"+target
    recdata = home+"/recently-used.xbel"
    
    def runs(app):
        try:
            # see if the application is running
            app = subprocess.check_output(["pgrep", app]).decode("utf-8")
        except subprocess.CalledProcessError:
            return False
        else:
            return True
    
    def get_lines():
        # retrieve information from the records:
        # -> get bookmark line *if* the application is in the exec= line
        with open(recdata) as infile:
            db = []
            for l in infile:
                if '<bookmark href="file://' in l:
                    sub = l
                elif 'exec="&apos;'+application in l:
                    db.append(sub)
        # fix bug in xbel -file in 15.04
        relevant = [l.split('="') for l in set(db) if all([not "/tmp" in l, "." in l])]
        relevant = [[it[1][7:-7], it[-2][:-10]] for it in relevant]
        relevant.sort(key=lambda x: x[1])
        return [item[0].replace("%20", " ") for item in relevant[::-1][:n]]
    
    def create_section(line):
        # create shortcut section
        name = line.split("/")[-1]
        return [[
            "[Desktop Action "+name+"]",
            "Name="+name,
            "Exec="+open_cmd+" '"+line+"'",
            "\n",
            ], name]
    
    def setup_dirs():
        # copy the global .desktop file to /usr/share/applications/
        glo = "/usr/share/applications/"+target
        if not os.path.exists(loc):
            shutil.copy(glo,loc)
    
    def edit_launcher(newdyn, target, actionlist):
        # read the current .desktop file
        ql = [list(item) for item in list(enumerate(open(loc).read().splitlines()))]
        # find the Actions= line
        currlinks = [l for l in ql if "Actions=" in l[1]]
        # split the line (if it exists)  by the divider as delimiter 
        linkline = currlinks[0][1].split("divider1")[0] if currlinks else None
        # define the shortcut sections, belonging to the dynamic section (below the divider)
        lowersection = [l for l in ql if "[Desktop Action divider1]" in l]
        # compose the new Actions= line
        addlinks = (";").join(actionlist) + ";"
        if linkline:
            newlinks = linkline + addlinks
            ql[currlinks[0][0]][1] = newlinks
            # get rid of the "dynamic" section  
            ql = ql[:lowersection[0][0]] if lowersection else ql
            # define the new file
            ql = [it[1] for it in ql]+newdyn
            with open(loc, "wt") as out:
                for l in ql:
                    out.write(l+"\n")
        else:
            newlinks = "Acrions="+addlinks
    
    setup_dirs()
    lines1 = []
    
    while True:
        time.sleep(2)
        # if the application does not run, no need for a check of .xbel
        if runs(application):
            lines2 = get_lines()
            # (only) if the list of recently used changed: edit the quicklist
            if lines1 != lines2:
                actionlist = ["divider1"]
                newdyn = [
                    "[Desktop Action divider1]",
                    "Name=" + 37*".",
                    "\n",
                    ]
                for line in lines2:
                    data = create_section(line)
                    actionlist.append(data[1])
                    section = data[0]
                    for l in section:
                        newdyn.append(l)
                edit_launcher(newdyn, target, actionlist)           
            lines1 = lines2
    
  2. Na seção principal do script, você pode definir várias opções:

    # --- set the number of docs to show in recently used
    n = 7
    # --- set the process name of the targeted application
    application = "soffice"
    #--- ONLY change the value below into "xdg-open" if you do not use LO preinstalled
    #    else the value should be the same as in application = (above)
    open_cmd = "soffice"
    # --- set the targeted .desktop file (e.g. "gedit.desktop")
    target = "libreoffice-writer.desktop"
    

    A maioria das opções fala por si, se você quiser adicionar a seção dinâmica ao LO-Writer launcher, deixe tudo como está. Caso contrário, defina o lançador apropriado.

  3. Teste- execute o script executando a partir de um terminal:

    python3 /path/to/dynamic_recent.py
    
  4. O script copiou o arquivo global .desktop para ~/.local/share/applications (nesse caso, ~/.local/share/applications/libreoffice-writer.desktop ). Arraste a cópia local para o lançador (caso contrário, você precisará fazer logout / entrada).

  5. Se tudo funcionar bem, adicione-o aos aplicativos de inicialização: Dash & gt; Aplicativos de inicialização & gt; Adicionar. Adicione o comando:

    python3 /path/to/dynamic_recent.py
    

Para usá-lo em outros aplicativos

Como mencionado, você pode facilmente usar o script para adicionar uma seção dinâmica "recentemente usada" ao (s) lançador (es) de outra aplicação. Para fazer isso, veja a configuração de gedit do exemplo para a seção head do script:

# --- set the number of docs to show in recently used
n = 7
# --- set the process name of the targeted application
application = "gedit"
#--- ONLY change the value below into "xdg-open" if you do not use LO preinstalled
#    else the value should be the same as in application = (above)
open_cmd = "gedit"
# --- set the targeted .desktop file (e.g. "gedit.desktop")
target = "gedit.desktop"

Como funciona

  • O script examina periodicamente o arquivo ~/.local/share/recently-used.xbel para encontrar arquivos correspondentes, abertos com LibreOffice (processname: soffice )

    Ele usa um algoritmo bastante rápido para fazer isso, "disparando" através do arquivo em uma única passagem, para recuperar as linhas necessárias (duas por "registro"). O resultado é que o script está com pouco suco.

  • Depois que as linhas relevantes são recuperadas do arquivo, as linhas são classificadas por data / hora, criando um "top ten" (ou qualquer outro número) dos arquivos usados mais recentemente do aplicativo correspondente.

  • SOMENTE se essa lista for alterada, o arquivo .desktop será atualizado.

Eu pude notar nem medir qualquer carga adicional no meu sistema, executando o script em segundo plano.

Testado em 14.04 / 15.10

Como restaurar o inicializador original

Basta remover a cópia local do lançador em ~/.local/share/applications

Notas

  • Caso você use o Editor de listas rápidas da Unity para editar seus lançadores (listas rápidas), deve evitar a edição de lançadores com uma seção "usada pela última vez" dinamicamente a partir desta resposta. As edições que você faz com o Editor da Quicklist serão imediatamente sobrescritas pelo script.

  • Você pode editar sua lista rápida manualmente, mas certifique-se de adicionar um novo item antes (no lado esquerdo de) divider1 na Actions= - line

    Actions=Window;Document; divider1 ;aap.sh;Todo;pscript_2.py;currdate;bulkmail_llJacob;verhaal;test doc;

    Todos os itens à direita de divider1 pertencem à seção atualizada dinamicamente.

Edição importante

Algumas melhorias importantes foram feitas:

  1. O script agora somente verifica o arquivo .xbel enquanto o aplicativo de destino é executado (já que não haverá alterações na lista usada recentemente se o aplicativo não for executado). O roteiro já estava com pouco suco, mas agora, ficar de olho apenas se o aplicativo for executado significa muito menos para o seu sistema.
  2. No 15.04+, o arquivo .xbel tinha duas menções de novos arquivos; um com e um sem extensão. O efeito disso agora é eliminado.
por Jacob Vlijm 19.03.2016 / 13:22