应用程序指示器图标在被点击之前不会改变

应用程序指示器图标在被点击之前不会改变

我有一个应用程序指示器,它以图标(以及文本标签)的形式显示月相/方位。当指示器进行更新时(每小时几次),图标会重新创建(作为 SVG 文件),因此图标会随时间而变化。

最近,除非我用鼠标单击图标(或标签),否则图标不会显示任何变化。我在 Ubuntu 14.04 64 位上,我的指标使用 Python 3 和 Appindicator3。

下面的代码代表了这个问题,它显示了一个图标,该图标应该每三秒变化一次(我将间隔设置为三秒以便快速查看问题 - 实际上图标最多每小时变化一次)。图标本身是一个 SVG 文件,显示数字计数,从零开始,每三秒增加一次。

我已经在 Ubuntu 12.04 和 Xubuntu 12.04(通过 VirtualBox)上进行测试,图标在每三秒更新时确实会发生变化。

在 Ubuntu 14.04 上测试,除非我单击图标,否则图标不会改变。如果我在每次更新时更改标签文本,图标也会改变,但前提是我不重复标签上的相同文本。

有人能证实这一点吗?我找不到错误报告,而且 Python AppIndicator 的 API 不再可用,所以我无法判断是否有东西发生了变化或被弃用。

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

仅供参考:已提交错误报告https://bugs.launchpad.net/ubuntu/+bug/1337620

答案1

我认为这是合理的,因为主题路径和图标名称没有改变,指示器图标不会更新/重新加载(为什么它应该失去一些周期来重新加载它?这是最佳的,不是吗?)。

嗯,libappindicator是为从文件加载的静态图标而设计的。(lp bug#812067: 需要 API:pixbuf 图标设置支持)。您想通过更改图标文件内容来解决这个问题。在您的情况下,这是可以的,但不适合一般用途,因为它需要更短的更新延迟(例如:120ms),即太多的文件 io 请求(打开、写入、关闭)。

  • 或者,你可以更改主题路径,这是一种技巧:

    self.indicator.set_icon_theme_path( os.getenv( "HOME" )+"./"*(self.count % 2) )
    self.indicator.set_icon_full( IndicatorTestIcon.SVG_ICON, str( self.count ) )
    
  • 或者更改名称(您可以使用与之前相同的方法,在两个名称之间交替):

    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:
    

顺便说一句,最好使用set_icon_fullset_icon已被弃用。(在 Ubuntu 14.04 上测试)

答案2

经过各种场景的测试后,最简单的解决方法(除了修复错误本身(假设它是一个错误))是来回交替图标文件的命名...

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

相关内容