Take the 2-minute tour ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free, no registration required.

I have an application indicator which shows the moon phase/orientation as its icon (along with a text label). When the indicator does an update (several times per hour), the icon is recreated (as an SVG file) and so the icon changes over time.

Recently, the icon is not showing any change unless I mouse click the icon (or label). I'm on Ubuntu 14.04 64 bit and my indicator uses Python 3 and Appindicator3.

The code below is representative of the issue and shows an icon which should change every three seconds (I made the interval three seconds to see the issue quickly - in reality the icon changes hourly at most). The icon itself is an SVG file and shows a numerical count, starting from zero and increments every three seconds.

I have tested on Ubuntu 12.04 and Xubuntu 12.04 (via VirtualBox) and the icon DOES change on each three second update.

Testing on Ubuntu 14.04, the icon does NOT change UNLESS I click on it. If I change the label text on each update, the icon WILL also change, but only if I don't repeat the SAME text for the label.

Is anyone able to confirm this please? I cannot find a bug report and the API for the Python AppIndicator is no longer available so I cannot tell if something has changed or been deprecated.

#!/usr/bin/env python3


try: from gi.repository import AppIndicator3
except: pass

from gi.repository import GLib, Gtk

import os


class IndicatorTestIcon:

    NAME = "indicator-test-icon"
    SVG_ICON = "." + NAME
    SVG_FILE = os.getenv( "HOME" ) + "/" + SVG_ICON + ".svg"


    def __init__( self ):
        self.count = 0

        self.indicator = AppIndicator3.Indicator.new( IndicatorTestIcon.NAME, "", AppIndicator3.IndicatorCategory.APPLICATION_STATUS )
        self.indicator.set_icon_theme_path( os.getenv( "HOME" ) )
        self.indicator.set_status( AppIndicator3.IndicatorStatus.ACTIVE )


    def main( self ):
        self.update()
        GLib.timeout_add_seconds( 3, self.update )
        Gtk.main()


    def update( self ):
        self.buildMenu()

        self.createIcon()

        self.indicator.set_icon( IndicatorTestIcon.SVG_ICON )

        #        self.indicator.set_label( "static label", "" ) # Using a static label, the icon does not change unless clicked with the mouse.
        self.indicator.set_label( str( self.count ), "" ) # Using a dynamic label (which does not repeat) DOES change the icon.

        self.count += 1

        return True


    def buildMenu( self ):
        menu = Gtk.Menu()

        quitMenuItem = Gtk.ImageMenuItem.new_from_stock( Gtk.STOCK_QUIT, None )
        quitMenuItem.connect( "activate", Gtk.main_quit )
        menu.append( quitMenuItem )

        self.indicator.set_menu( menu )
        menu.show_all()


    def createIcon( self ):
        header = '<?xml version="1.0" standalone="no"?>' \
            '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' \
            '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 100 100">'

        text = '<g>' \
            '<text x="0" y="75" font-family="Verdana" font-size="100" fill="white" >' + str( self.count ) + '</text>' \
            '</g>'

        footer = '</svg>'

        with open( IndicatorTestIcon.SVG_FILE, "w" ) as f:
            f.write( header + text + footer )
            f.close()


if __name__ == "__main__": IndicatorTestIcon().main()

FYI: Submitted a bug report https://bugs.launchpad.net/ubuntu/+bug/1337620

share|improve this question

2 Answers 2

I think this is reasonable, as theme path & icon name didn't change there will be no update/reload for indicator icon (why it should loose some cycles to reload it? This is optimum, no?!).

Well, libappindicator was designed for static icons loaded from files. ( lp bug#812067: API needed: pixbuf icon setting support ). You want to make a workaround on that by changing icon file contents. In your case its ok, but not for general use where it needs shorter update delay (ex: 120ms) ie, too much file io requests (open,write,close).

  • Either, you change theme path this is kind of trick:

    self.indicator.set_icon_theme_path( os.getenv( "HOME" )+"./"*(self.count % 2) )
    self.indicator.set_icon_full( IndicatorTestIcon.SVG_ICON, str( self.count ) )
    
  • Or change name (you can use same previous method, alternating between 2 names):

    SVG_ICON = "." + NAME+ "_{0}"
    ...
    self.indicator.set_icon_full( IndicatorTestIcon.SVG_ICON.format(self.count % 2) , str( self.count ) )
    ...
    with open( IndicatorTestIcon.SVG_FILE.format(self.count % 2), "w" ) as f:
    

BTW, it better to use set_icon_full, set_icon is deprecated. (Tested on Ubuntu 14.04)

share|improve this answer
    
I'd already tried alternating the filename/path as a last resort workaround (as you suggested). Sadly the API has not been updated (from the links I've found). I expect when calling a function which sets an icon/path/whatever, that function should do it, unless documented otherwise. Further, this behavior works in Ubuntu 12.04 - 13.10 and has seemingly changed at some point in 14.04 and I was hoping someone else may be able to verify. There was another answer here before (I think confirming my suspicions) but I guess the moderator has removed it. –  Bernmeister Jul 4 at 14:40
    
Actually mine is 14.04, python-appindicator 12.10.1+13.10.20130920-0ubuntu4 alternating theme path/or icon name works. I will try VM for an older release, and give you a feedback. –  Sneetsher Jul 4 at 18:59
up vote 0 down vote accepted

After testing various scenarios, the simplest workaround (apart from the bug itself being fixed assuming that it is a bug) is to alternate the naming of the icon file back and forth...

#!/usr/bin/env python3


from gi.repository import AppIndicator3, GLib, Gtk

import glob, os


class IndicatorTestIcon:

    NAME = "indicator-test-icon"
    ICON_STATE = True


    def __init__( self ):
        self.count = 0

        for file in glob.glob( os.getenv( "HOME" ) + "/." + IndicatorTestIcon.NAME + "*.svg" ):
            print(file)
            os.remove( file )

        self.indicator = AppIndicator3.Indicator.new( IndicatorTestIcon.NAME, "", AppIndicator3.IndicatorCategory.APPLICATION_STATUS )
        self.indicator.set_icon_theme_path( os.getenv( "HOME" ) )
        self.indicator.set_status( AppIndicator3.IndicatorStatus.ACTIVE )


    def main( self ):
        self.update()
        GLib.timeout_add_seconds( 3, self.update )
        Gtk.main()


    def update( self ):

        print( self.count )
        self.buildMenu()

        self.createIcon()

        self.indicator.set_label( "static label", "" )
        self.indicator.set_icon_full( self.getIconName(), "" )

        self.count += 1

        self.toggleIconState()
        return True


    def buildMenu( self ):
        menu = Gtk.Menu()

        quitMenuItem = Gtk.ImageMenuItem.new_from_stock( Gtk.STOCK_QUIT, None )
        quitMenuItem.connect( "activate", Gtk.main_quit )
        menu.append( quitMenuItem )

        self.indicator.set_menu( menu )
        menu.show_all()


    def createIcon( self ):
        header = '<?xml version="1.0" standalone="no"?>' \
            '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' \
            '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 100 100">'

        text = '<g>' \
            '<text x="0" y="75" font-family="Verdana" font-size="100" fill="white" >' + str( self.count ) + '</text>' \
            '</g>'

        footer = '</svg>'

        with open( self.getIconFile(), "w" ) as f:
            f.write( header + text + footer )
            f.close()


    def getIconName( self ):
        if IndicatorTestIcon.ICON_STATE: return "." + IndicatorTestIcon.NAME + "-1"

        return "." + IndicatorTestIcon.NAME + "-2"


    def getIconFile( self ):
        if IndicatorTestIcon.ICON_STATE: return os.getenv( "HOME" ) + "/." + IndicatorTestIcon.NAME + "-1.svg"

        return os.getenv( "HOME" ) + "/." + IndicatorTestIcon.NAME + "-2.svg"


    def toggleIconState( self ): IndicatorTestIcon.ICON_STATE = not IndicatorTestIcon.ICON_STATE


if __name__ == "__main__": IndicatorTestIcon().main()
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.