Desde que parece ser a ocasião para fazer esta pergunta já tem uma resposta , eu estou respondendo esta questão como explicação detalhada sobre como foi feito (em python
)
Indicador básico estático
Como o Ubuntu Mate, de 15,10, suporta indicadores, não há muita diferença entre escrever um indicador e um aplicativo de painel para o Mate. Portanto, este link é um bom ponto de partida para um indicador básico em python
, usando a API AppIndicator3
. O link é um bom começo, mas não fornece nenhuma informação sobre como mostrar o texto no indicador, muito menos como atualizar o texto (ou ícone). No entanto, com algumas adições, isso leva a um "quadro" básico de um indicador, conforme abaixo. Ele mostrará um ícone, um rótulo de texto e um menu:
#!/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
class Indicator():
def __init__(self):
self.app = 'test123'
iconpath = "/opt/abouttime/icon/indicator_icon.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())
self.indicator.set_label("1 Monkey", self.app)
def create_menu(self):
menu = Gtk.Menu()
# menu item 1
item_1 = Gtk.MenuItem('Menu item')
# item_about.connect('activate', self.about)
menu.append(item_1)
# separator
menu_sep = Gtk.SeparatorMenuItem()
menu.append(menu_sep)
# quit
item_quit = Gtk.MenuItem('Quit')
item_quit.connect('activate', self.stop)
menu.append(item_quit)
menu.show_all()
return menu
def stop(self, source):
Gtk.main_quit()
Indicator()
signal.signal(signal.SIGINT, signal.SIG_DFL)
Gtk.main()
Na linha AppIndicator3.IndicatorCategory.OTHER
, a categoria é definida, conforme explicado em este link (parcialmente desatualizado) . Definir a categoria correta é importante, a.o. para colocar o indicador em uma posição apropriada no painel.
O principal desafio; como atualizar o texto do indicador e / ou ícone
O verdadeiro desafio não é como escrever um indicador básico, mas como periodicamente atualizar o texto e / ou ícone do seu indicador, desde que você queira que ele mostre o tempo (textual). Para fazer o indicador funcionar corretamente, não podemos simplesmente usar threading
para iniciar um segundo processo para atualizar periodicamente a interface. Bem, na verdade nós podemos, mas a longo prazo, isso levará a conflitos, como eu descobri.
Aqui é onde entra GObject
, como é colocado neste link (também desatualizado) :
chama gobject.threads_init()
na inicialização do aplicativo. Em seguida, você inicia seus encadeamentos normalmente, mas certifique-se de que os encadeamentos nunca realizem nenhuma tarefa da GUI diretamente. Em vez disso, você usa gobject.idle_add
para agendar a tarefa da GUI para ser executada no thread principal
Quando substituímos gobject.threads_init()
por GObject.threads_init()
e gobject.idle_add
por GObject.idle_add()
, praticamente temos a versão atualizada de como executar encadeamentos em um aplicativo Gtk
. Um exemplo simplificado, mostrando um número crescente de Monkeys:
#!/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
class Indicator():
def __init__(self):
self.app = 'test123'
iconpath = "/opt/abouttime/icon/indicator_icon.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())
self.indicator.set_label("1 Monkey", self.app)
# the thread:
self.update = Thread(target=self.show_seconds)
# daemonize the thread to make the indicator stopable
self.update.setDaemon(True)
self.update.start()
def create_menu(self):
menu = Gtk.Menu()
# menu item 1
item_1 = Gtk.MenuItem('Menu item')
# item_about.connect('activate', self.about)
menu.append(item_1)
# separator
menu_sep = Gtk.SeparatorMenuItem()
menu.append(menu_sep)
# quit
item_quit = Gtk.MenuItem('Quit')
item_quit.connect('activate', self.stop)
menu.append(item_quit)
menu.show_all()
return menu
def show_seconds(self):
t = 2
while True:
time.sleep(1)
mention = str(t)+" Monkeys"
# apply the interface update using GObject.idle_add()
GObject.idle_add(
self.indicator.set_label,
mention, self.app,
priority=GObject.PRIORITY_DEFAULT
)
t += 1
def stop(self, source):
Gtk.main_quit()
Indicator()
# this is where we call GObject.threads_init()
GObject.threads_init()
signal.signal(signal.SIGINT, signal.SIG_DFL)
Gtk.main()
Esse é o princípio. No indicador real em esta resposta , tanto o tempo de loop quanto o texto do indicador foram determinados por um módulo secundário, importado no roteiro, mas a idéia principal é a mesma.