web-dev-qa-db-fra.com

Comment puis-je écrire une application / indicateur de panneau mis à jour dynamiquement?

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.

10
j0h

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)

Indicateur de base statique

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:

enter image description here

#!/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 défi principal; comment mettre à jour le texte de l'indicateur et/ou l'icône

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:

enter image description here

#!/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.

14
Jacob Vlijm