A ação personalizada do botão direito do mouse no Unity Launcher mantém o cursor ocupado por 20 segundos

14

Para ter uma opção "minimizar janela" clicando com o botão direito do mouse em um ícone no iniciador do Unity (Ubuntu 14.04), segui as instruções detalhadas aqui sobre como alterar um .desktoparquivo e criei um Firefoxiniciador personalizado na ~/.local/share/applications/pasta. A parte relevante do arquivo .desktop é:

Actions=NewWindow;NewPrivateWindow;Minimize

[Desktop Action NewWindow]
Name=Open a New Window
Exec=firefox -new-window
OnlyShowIn=Unity;

[Desktop Action NewPrivateWindow]
Name=Open a New Private Window
Exec=firefox -private-window
OnlyShowIn=Unity;

[Desktop Action Minimize]
Name=Minimize Windows
Exec=sh /home/myusername/Documents/xdotool_sh/minimize.sh firefox
OnlyShowIn=Unity;

A ação da área de trabalho "Minimizar" chama um script de shell simples, minimize.shcom o seguinte conteúdo:

#/bin/bash
name=$1
for i in $(xdotool search --class "$name"); do
    xdotool windowminimize $i
done

O script usa xdotool, que pode ser instalado a partir dos repositórios oficiais, para encontrar todas as firefoxjanelas, iterar sobre elas e minimizá-las.

O script funciona e a opção de menu à direita do iniciador "Minimizar Windows" também funciona, mas assim que as janelas são minimizadas, o ponteiro do mouse entra no modo "ocupado" e permanece assim por cerca de 20 segundos (embora as ações do mouse ainda estejam responsivo).

Alguém sabe por que iniciar um script de shell a partir de uma opção de menu à direita no Unity pode levar a esse comportamento?

EDIT : Aparentemente, o período de espera é inevitável, conforme explicado na resposta de Jacob Vlijm. Como o mouse permanece responsivo, evitar a transformação do ponteiro na roda giratória é uma solução alternativa estética parcial, conforme explicado no askubuntu .

EDIT2 : dar ao sistema uma janela falsa é uma solução melhor, conforme explicado por Jacob abaixo.

Cosmin Saveanu
fonte
Oi Cosmin, eu adicionei outra solução bastante limpa, eu acho.
Jacob Vlijm 11/03/16
Obrigado Jacob. Eu estava pensando sobre esse tipo de solução, mas não sabia como isso poderia ser feito. É ótimo que exista uma solução.
Cosmin Saveanu 11/03/16

Respostas:

18

Excelente pergunta.

A causa

Normalmente, ao iniciar aplicativos da GUI a partir do Unity Launcher, o iniciador espera uma janela aparecer. Enquanto aguarda, mostra a "roda giratória". No entanto, não vai esperar para sempre; Após cerca de 20 segundos, o iniciador assume que a janela não aparecerá e deixa de esperar.

1. O comando principal do iniciador de um aplicativo

Em um .desktoparquivo, referente à primeira Exec=linha (o comando principal), você pode dizer ao iniciador para aguardar ou não, em uma linha:

StartupNotify=true

para esperar, ou

StartupNotify=false

para não esperar.

2. Itens da lista rápida de um iniciador

Para possíveis itens da lista rápida (clique com o botão direito do mouse) de um iniciador, no entanto, o valor padrão é StartupNotify=true. Infelizmente, esse valor é fixo e não pode ser alterado por nada.

Isso significa que, se você iniciar qualquer comando clicando com o botão direito do mouse em um ícone do lançador no Unity Launcher, o lançador estará esperando uma janela e aguardará, mostrando a roda giratória.

A linha inferior é que, embora possa ser explicado, parece não haver solução para o problema no momento, além de criar um iniciador dedicado para o seu script e adicionar a linha StartupNotify=falseao arquivo.

A prova

Você pode testar o comportamento você mesmo. Crie dois lançadores:

[Desktop Entry]
Name=Test
Exec=sh /home/myusername/Documents/xdotool_sh/minimize.sh firefox
Type=Application
StartupNotify=true

e:

[Desktop Entry]
Name=Test
Exec=sh /home/myusername/Documents/xdotool_sh/minimize.sh firefox
Type=Application
StartupNotify=false

Salve-os como test1.desktope test2.desktoparraste os dois lançadores para o iniciador do Unity. Clique neles e veja a diferença de comportamento.


Editar; se realmente o incomoda, alimente o Unity com uma janela falsa

Se você possui muitos scripts em listas rápidas e / ou realmente o incomoda, há outra solução cosmética; podemos fingir , invisíveis (totalmente transparentes) para mostrar uma janela, a ser incluída no seu script. seu script seria então (por exemplo)

#/bin/bash
name=$1
for i in $(xdotool search --class "$name"); do
    xdotool windowminimize $i
done
fake_window

onde o comando fake_windowchamará nossa janela (falsa), fazendo o Unity terminar a roda giratória.

Como configurar

  1. Crie, se ainda não existir, o diretório ~/bin
  2. Copie o script abaixo em um arquivo vazio, salve-o como fake_window(sem extensão) ~/bin e torne-o executável

    #!/usr/bin/env python3
    from gi.repository import Gtk
    from threading import Thread
    import time
    import subprocess
    
    """
    This is a self-destroying window, to "feed" Unity a fake-window, preventing
    the launcher to show a spinning wheel, waiting for a window to appear.
    Include the command to run this script at the end of the (your) script.
    """
    
    class FakeWin(Gtk.Window):
    
        def __init__(self):
            Gtk.Window.__init__(self, title="1526closeme")
            Thread(target = self.close).start()
    
        def close(self):
            t = 0
            while t < 150:
                time.sleep(0.2)
                try:
                    pid = subprocess.check_output(["pgrep", "-f", "fake_window"])\
                          .decode("utf-8").strip()
                    subprocess.Popen(["kill", pid])
                    break
                except subprocess.CalledProcessError:
                    pass
                t += 1
    
    def fakewindow():
        window = FakeWin()
        # make our window transparent
        window.set_opacity(0)
        window.set_default_size(0,0)
        window.show_all()
        Gtk.main()
    
    fakewindow()
  3. Adicione ao final do seu script o comando:

    fake_window
  4. Sair e voltar (ou executarsource ~/.profile)

É isso aí, agora a roda gira apenas enquanto o script for executado.

Explicação

O script faz criar uma janela minimalista. A janela, no entanto, é totalmente transparente e tem um tamanho de 0x0 pixels e, portanto, é invisível. Ele se destruirá instantaneamente quando existir.

Chamando a janela no final do seu script, você satisfará o desejo da Unity por uma janela, parando a roda para girar.

Jacob Vlijm
fonte
Obrigado pela explicação detalhada e pelas edições da pergunta. Dá idéias sobre possíveis soluções alternativas.
Cosmin Saveanu
Ótima idéia - dando uma janela falsa. Eu gosto
Sergiy Kolodyazhnyy 02/08
@Serg a fraude eo engano, mas funciona :)
Jacob Vlijm
4

Só queria adicionar uma implementação alternativa de fake_window que é um pouco mais simples e não aciona avisos de python em um sistema Ubuntu 16.04.

#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '3.0')

from gi.repository import Gtk
from gi.repository import GLib

"""
This is a self-destroying window, to "feed" Unity a fake-window, preventing
the launcher to show a spinning wheel, waiting for a window to appear.
Include the command to run this script at the end of the (your) script.
"""

def timer_cb():
    Gtk.main_quit()
    return False

def show_cb(widget, data=None):
    GLib.timeout_add(500, timer_cb)

def fakewindow():
    window = Gtk.Window()
    # make our window transparent
    window.set_opacity(0)
    window.set_default_size(0,0)

    window.connect("show", show_cb)

    window.show_all()

    Gtk.main()

fakewindow()
Digikata
fonte
Agradável! nunca notei essa adição até agora :)
Jacob Vlijm