Как я могу написать динамически обновляемое приложение панели / индикатор?

12

Я пытаюсь написать несколько панельных приложений для Ubuntu Mate. Я знаю C / C ++ и SDL достаточно хорошо. Я видел страницу GitHub для приложений панели Mate-University, но не могу заставить ее работать должным образом / у меня есть хоть какое-то время.

Мне просто интересно, есть ли какой-нибудь простой способ написать панель приложений? Я не говорю об использовании пользовательского средства запуска приложений, я хотел бы добавить новые функциональные возможности на панель, но я не уверен, как это сделать. Учебное пособие или описание написания приложений панели могут быть действительно полезными.

j0h
источник

Ответы:

16

Поскольку у того, что кажется поводом для того, чтобы задать этот вопрос, уже есть ответ , я отвечаю на этот вопрос в качестве расширенного объяснения того, как это было сделано (в python)

Основной статический индикатор

Поскольку Ubuntu Mate из 15,10 поддерживает индикаторы, между написанием индикатора и панельным приложением для Mate нет большой разницы. Таким образом, эта ссылка является хорошей отправной точкой для базового индикатора при pythonиспользовании AppIndicator3API. Ссылка является хорошим началом, но не предоставляет никакой информации о том, как отображать текст на индикаторе, не говоря уже о том, как обновить текст (или значок). Тем не менее, с некоторыми добавлениями, это приводит к базовой «рамке» индикатора, как показано ниже. Он покажет значок, текстовую метку и меню:

введите описание изображения здесь

#!/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()

В строке AppIndicator3.IndicatorCategory.OTHERопределяется категория, как объяснено в этой (частично устаревшей) ссылке . Важно установить правильную категорию, чтобы установить индикатор в нужном месте на панели.

Основной вызов; как обновить текст индикатора и / или значок

Реальная проблема не в том, как написать базовый индикатор, а в том, как периодически обновлять текст и / или значок вашего индикатора, поскольку вы хотите, чтобы он показывал (текстовое) время. Для правильной работы индикатора мы не можем просто использовать threadingвторой процесс для периодического обновления интерфейса. Ну, на самом деле мы можем, но в долгосрочной перспективе, как я выяснил, это приведет к конфликтам.

Вот, что GObjectвходит, как указано в этой (также устаревшей) ссылке :

позвоните gobject.threads_init()при инициализации приложения. Затем вы запускаете свои потоки в обычном режиме, но убедитесь, что потоки никогда не выполняют задачи GUI напрямую. Вместо этого вы используете gobject.idle_addдля планирования задачи GUI для выполнения в основном потоке

Когда мы заменим gobject.threads_init() на GObject.threads_init()и gobject.idle_addна GObject.idle_add(), мы в значительной степени имеем обновленную версию о том , как запускать потоки в Gtkприложении. Упрощенный пример, показывающий все большее количество обезьян:

введите описание изображения здесь

#!/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()

Это принцип. В фактическом индикаторе в этом ответе и время цикла, и текст индикатора были определены вторичным модулем, импортированным в скрипт, но основная идея та же.

Якоб Влейм
источник