View Single Post
Posts: 133 | Thanked: 172 times | Joined on Jul 2009 @ Travel bag
#28
Request to the Python experts here

I think I know the issue with this SVGClock performance..

Actually I am rendering all the SVG components of the clock together. Since the static components such as the background ( clock face, clock markings) and foreground ( Clock frame, Clock glass, frame) parts get rendered every time along with the moving parts such as the Minute/Hour hand, they end up consuming far too many CPU cycles, I think. This overloads device that we have on hand, making the N8x0 too slow, as reported by Addison.

I would really appreciate it, if some one can take a look at the code and help tell me how I can do some kind of buffering or pre-rendering of the above static components ( Background and Foreground parts), so that they are not read and rendered every time the second/minute hands are being refreshed. I believe this can be done within Python itself ( without worrying too much about, Cairo or rsvg)

To look at the code, pls see SVGClock.py under /usr/lib/hildon-desktop/SVGClock.py

If I get some directions on this buffering of the SVG files and pre rendering, I will be more than happy to package this with all dependencies to release it to Extras-Devel and then Extras..

TiA
Shin

Though lengthy, thought I will paste the code here for anyone interested:

Code:
#All imports we need
import sys, os
import gobject
import pango
import pygtk
pygtk.require('2.0')
import gtk
from gtk import gdk
import hildondesktop
import cairo
from datetime import datetime
import time
import rsvg
import math

# set this to False to disable display of seconds and update 
# only once per minute (saves CPU cycles on the tablet)
enable_seconds = True

supports_alpha = False

class SVGClock(hildondesktop.HomeItem):
    def __init__(self):
        hildondesktop.HomeItem.__init__(self)

        self.set_resize_type(hildondesktop.HOME_ITEM_RESIZE_BOTH)
        self.set_size_request(200, 200)
        self.connect("expose-event", self.expose)
        self.connect("screen-changed", self.screen_changed)
        self.connect ("background", self.set_timer, False)
        self.connect ("foreground", self.set_timer, True)
        self.connect ("unrealize", self.unrealize)

        # set a timeout to update the clock, depending
        # on whether we are in the foreground or background
        self.timer = None
        self.set_timer(self, True)

        self.show_all()

    def expose(self, widget, event):

        global supports_alpha

        width, height = self.allocation[2], self.allocation[3]

        #Get a cairo context
        cr = widget.window.cairo_create()

        if supports_alpha == True:
            cr.set_source_rgba(0.0, 0.0, 0.0, 0.0) # Transparent
        else:
            cr.set_source_rgb(1.0, 1.0, 1.0) # Opaque white

        # Draw the background
        cr.set_operator(cairo.OPERATOR_SOURCE)
        cr.paint()

        #And draw everything we want
        if width < height:
           radius = float(width)/2 - 0.8
        else:
           radius = float(height)/2 - 0.8
        
        SVGH_Drop_Shadow = rsvg.Handle(file="/home/user/MyDocs/Themes/default/clock-drop-shadow.svg")
        SVGH_Face = rsvg.Handle(file="/home/user/MyDocs/Themes/default/clock-face.svg")
        SVGH_Face_Shadow = rsvg.Handle(file="/home/user/MyDocs/Themes/default/clock-face-shadow.svg")
        SVGH_Marks = rsvg.Handle(file="/home/user/MyDocs/Themes/default/clock-marks.svg")
        SVGH_Frame = rsvg.Handle(file="/home/user/MyDocs/Themes/default/clock-frame.svg")
        SVGH_Glass = rsvg.Handle(file="/home/user/MyDocs/Themes/default/clock-glass.svg")
        SVGH_Hour_Hand = rsvg.Handle(file="/home/user/MyDocs/Themes/default/clock-hour-hand.svg")
        SVGH_Minute_Hand = rsvg.Handle(file="/home/user/MyDocs/Themes/default/clock-minute-hand.svg")
        SVGH_Second_Hand = rsvg.Handle(file="/home/user/MyDocs/Themes/default/clock-second-hand.svg")    

        cr.scale(2.0,2.0)
        cr.save()
        # Draw foreground
        SVGH_Face_Shadow.render_cairo(cr)
        SVGH_Glass.render_cairo(cr)
        SVGH_Frame.render_cairo(cr)

        # Draw Background
        cr.set_operator(cairo.OPERATOR_OVER)
        SVGH_Drop_Shadow.render_cairo(cr)
        SVGH_Face.render_cairo(cr)
        SVGH_Marks.render_cairo(cr)
        
        #Draw the clock glass face with shadow
        cr.set_operator(cairo.OPERATOR_OVER)
        SVGH_Glass.render_cairo(cr)	


        cr.translate(50,50)
        cr.save()

        #Draw the hours/minutes and seconds hands		
        time = datetime.now()
        hour = time.hour
        minutes = time.minute
        seconds = time.second

        cr.set_operator(cairo.OPERATOR_OVER)
        #cr.rotate((360/12) * (hour+9) * (3.141593/180))
        cr.rotate(((360/12) * (hour+9) * (3.141593/180)) + (((360/60) * minutes * (3.141593/180)) / 12))
        SVGH_Hour_Hand.render_cairo(cr)
        cr.restore()
        cr.save()

        cr.rotate((360/60) * (minutes+45) * (3.141593/180))
        SVGH_Minute_Hand.render_cairo(cr)
        cr.restore()
        cr.save()

        # only draw seconds when in foreground
        if enable_seconds: # disable seconds, to much work for little tablets
           cr.rotate((360/60) * (seconds+45) * (3.141593/180))
           cr.set_operator(cairo.OPERATOR_OVER)
           SVGH_Second_Hand.render_cairo(cr)
           cr.restore()
        
        #Once everything has been drawn, create our XShape mask
        #Our window content is contained inside the big circle,
        #so let's use that one as our mask
        """pm = gtk.gdk.Pixmap(None, width, height, 1)
        pmcr = pm.cairo_create()
        pmcr.arc(float(width)/2, float(height)/2, radius, 0, 2.0*3.14)
        pmcr.fill()
        pmcr.stroke()
        #Apply input mask
        self.input_shape_combine_mask(pm, 0, 0)"""

        return False

    def screen_changed(self, widget, old_screen=None):
        global supports_alpha
        # print "screen changed"

        # To check if the display supports alpha channels, get the colormap
        screen = self.get_screen()
        colormap = screen.get_rgba_colormap()
        if colormap == None:
            # print 'Your screen does not support alpha channels!'
            colormap = screen.get_rgb_colormap()
            supports_alpha = False
        else:
            # print 'Your screen supports alpha channels!'
            supports_alpha = True

        # Now we have a colormap appropriate for the screen, use it
        self.set_colormap(colormap)

        return False
#        return True


    def unrealize(self, widget, date=None):
        # cancel timeout
        if self.timer:
            v = gobject.source_remove(self.timer)
            print "canceled svgclock timeout:", v
            self.timer = None

    def set_timer(self, widget, on):
        # when called first time from __init__ widget is None
        if self.timer != None:
            # print "removing old timer"
            gobject.source_remove(self.timer)
        if on:
            # print "creating new timer"
            delay = 1000 if enable_seconds else 60000
            self.timer = gobject.timeout_add(delay, self.update)
            # repaint immediately when coming to the foreground
            self.update()

    def update(self):
        # print "updating svgclock"
        self.queue_draw()
        return True

def hd_plugin_get_objects():
    plugin = SVGClock()
    return [plugin]

Last edited by shin; 2010-01-12 at 16:59. Reason: pasted the code for svgclock.y for reference
 

The Following 2 Users Say Thank You to shin For This Useful Post: