J'essaie d'écrire des applications de panneau pour Ubuntu Mate. Je connais assez bien C/C++ et SDL. J'ai vu la page github des applications du panneau Mate-University, mais je ne parviens pas à le faire fonctionner correctement.
Je me demande simplement s'il existe une avenue facile pour écrire des applications de panel? Je ne parle pas de l'utilisation du lanceur d'applications personnalisé, je voudrais ajouter de nouvelles fonctionnalités au panneau, mais je ne sais pas comment faire. Un tutoriel ou une description de l'écriture d'applications de panneau pourrait être très utile.
Puisque ce qui semble être l’occasion de poser déjà cette question a une réponse , je réponds à cette question par une explication détaillée de la façon dont cela a été fait (dans python
)
Depuis Ubuntu Mate, à partir de 15,10, prend en charge les indicateurs, il n’ya pas beaucoup de différence entre l’écriture d’un indicateur et celle d’un panneau pour Mate. Par conséquent, ce lien est un bon point de départ pour un indicateur de base dans python
, à l'aide de l'API AppIndicator3
. Le lien est un bon début, mais ne fournit aucune information sur la façon d'afficher du texte sur l'indicateur, encore moins sur la façon de mettre à jour le texte (ou l'icône). ). Néanmoins, avec quelques ajouts, cela conduit à un "cadre" de base d'un indicateur comme ci-dessous. Il montrera une icône, une étiquette de texte et un 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()
Dans la ligne AppIndicator3.IndicatorCategory.OTHER
, la catégorie est définie, comme expliqué dans ce lien (partiellement obsolète) . Définir la bonne catégorie est important, a.o. mettre l'indicateur dans une position appropriée dans le panneau.
Le véritable défi n’est pas de savoir comment écrire un indicateur de base, mais comment mettre à jour périodiquement le texte et/ou l’icône de votre indicateur, car vous souhaitez il montre le temps (textuel). Pour que l'indicateur fonctionne correctement, nous ne pouvons pas simplement utiliser threading
pour démarrer un deuxième processus afin de mettre à jour l'interface périodiquement. En fait, nous pouvons le faire, mais à long terme, cela entraînera des conflits, comme je l’ai découvert.
Voici où GObject
entre, comme il est mis dans ce lien (également obsolète) :
appelez gobject.threads_init()
à l'initialisation de l'application. Ensuite, vous lancez vos threads normalement, mais assurez-vous qu'ils ne font jamais directement de tâches d'interface graphique. À la place, vous utilisez gobject.idle_add
pour planifier l'exécution d'une tâche d'interface graphique dans le thread principal
Lorsque nous remplaçons gobject.threads_init()
par GObject.threads_init()
et gobject.idle_add
par GObject.idle_add()
, nous disposons à peu près de la version mise à jour de la procédure d'exécution des threads dans une application Gtk
. Un exemple simplifié, montrant un nombre croissant de singes:
#!/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()
C'est le principe. Dans l'indicateur réel dans cette réponse , le temps de boucle et le texte de l'indicateur ont été déterminés par un module secondaire, importé dans le script, mais l'idée principale est la même.