Is it possible to add an Animation with AppIndicator3?

320 Views Asked by At

I'm trying to create a simple AppIndicator with Python. The code is pretty similar with:

import gi
from gi.repository import Gtk
from gi.repository import AppIndicator3 as appindicator

APPINDICATOR_ID = 'myapp'

def main():
    indicator = appindicator.Indicator.new(APPINDICATOR_ID, '/usr/share/myapp/images/icon.svg', appindicator.IndicatorCategory.SYSTEM_SERVICES)
    indicator.set_status(appindicator.IndicatorStatus.ACTIVE)
    Gtk.main()

It works very well, but I would like to introduce an animated icon. A blinking icon for example. Not a static one.

I tried to convert the SVG file to GIF, but it does not work as well.

Is there a way to create a GdkPixbuf.PixbufAnimation (example) within AppIndicator3?

If yes, How can I do it?

2

There are 2 best solutions below

2
On

I don't know if my answer will work for you but I see you are only importing libraries, assigning a variable, and defining some code. You may want to have the main(): code loop by typing:

This will give you the option to add return True or return False:

import gi
from gi.repository import Gtk
from gi.repository import AppIndicator3 as appindicator

APPINDICATOR_ID = 'myapp'

def main():
    indicator = appindicator.Indicator.new(APPINDICATOR_ID, '/usr/share/myapp/images/icon.svg', appindicator.IndicatorCategory.SYSTEM_SERVICES)
    indicator.set_status(appindicator.IndicatorStatus.ACTIVE)
    Gtk.main()

while main():
    pass

Or if you want the code to keep going until you click the stop button:

import gi
from gi.repository import Gtk
from gi.repository import AppIndicator3 as appindicator

APPINDICATOR_ID = 'myapp'

def main():
    indicator = appindicator.Indicator.new(APPINDICATOR_ID, '/usr/share/myapp/images/icon.svg', appindicator.IndicatorCategory.SYSTEM_SERVICES)
    indicator.set_status(appindicator.IndicatorStatus.ACTIVE)
    Gtk.main()

main()
0
On

I found a workaround for this. Specially, if you are trying to configure a GIF.

For me, create a manual GIF worked. This solution requires a better approach related to concurrency but the prototype is here:

import gi
import time
import signal
import threading

gi.require_version('Gtk', '3.0')
gi.require_version('AppIndicator3', '0.1')

from gi.repository import Gtk, GLib
from gi.repository import AppIndicator3 as appindicator

APPINDICATOR_ID = 'myapp'

finished = False

def change_icon(indicator, index=5):
    indicator.set_icon("spinner-%s.svg" % str(index))

def render_icon(indicator):
    i = 0
    while True:
        # I have 10 SVG images
        index = (i % 10)
        GLib.idle_add(change_icon, indicator, index)
        time.sleep(0.5)
        if finished:
            break
        i += 1

def on_click(widget):
    global finished
    finished = True
    Gtk.main_quit()

def main():
    indicator = appindicator.Indicator.new(APPINDICATOR_ID, 'spinner-0.svg', appindicator.IndicatorCategory.SYSTEM_SERVICES)
    indicator.set_status(appindicator.IndicatorStatus.ACTIVE)

    menu = Gtk.Menu()
    quit = Gtk.MenuItem('Quit')
    quit.connect('activate', on_click)
    menu.append(quit)

    menu.show_all()

    indicator.set_menu(menu)

    thread = threading.Thread(target=render_icon, args=(indicator,))
    thread.daemon = True
    thread.start()

    signal.signal(signal.SIGINT, signal.SIG_DFL)
    Gtk.main()

main()

I created a spinner with 10 different frames and I can iterate using a Thread and set_icon + GLib.iddle_add().

Again, it requires a better solution in terms of Thread concorrency, but it works as a starting point.