Hello, Jérôme!

On Fri, 2008-02-22 at 19:43 +0100, Jérôme Chabod wrote:
> Indeed, much nicer like this. I vote for your version !
> 
> A few remarks:
> * the bug is not really misterious: to fix it, replace trayicon.py
> line 314 with "self.__current_pixbuf = self.__icon" ("__" are missing)

Thanks, I've fixed that :)

> * although performance does not seems to be a problem,  the code could
> be more efficient if you copy the icon only the first time (when ratio
> is 0.0), it will preserve the cached download icon, whereas all other
> icon with a piece of progress bar will be garbage collected anyway, so
> no need to preserve them.

Well, because of the alpha channel, I have to copy the icon every time I
draw a progressbar on it (or else I would modify the current pixmap and
after some time, the progress bar would have a solid background).

> * the tray icon is drawned on every ratio change, it happens very
> offen (around 100*10 time during my big episodes download) and given
> that the icon is 48 pixels big, only 48 are idealy needed. At least,
> you could  improve this  by drawing only on integer percentage change,
> it would then  only happen 100*.

I have updated the code so it only updates the progress bar when the
progress meter changes for more than 3 percent-points, so we save a lot
of updates and it doesn't get noticed in the tray icon (even at maximum
size). 100/3 ~ 30 pixels - given that we subtract some pixels for the
padding and the border, that will be about one pixel in full size.

I've also fixed a related problem where cancelling a download in a
two-download scenario would result in the cancelled download being
counted as finished in the complete progress.

Please test this patch and tell me what you think. If everything's okay,
I will commit it into SVN trunk.

Thanks,
Thomas
Index: src/gpodder/trayicon.py
===================================================================
--- src/gpodder/trayicon.py	(revision 579)
+++ src/gpodder/trayicon.py	(working copy)
@@ -38,6 +38,7 @@
 
 from gpodder import services
 from gpodder import util
+from gpodder import draw
 
 from libgpodder import gPodderLib
 
@@ -88,6 +89,8 @@
             self.__icon = gtk.icon_theme_get_default().load_icon(gtk.STOCK_DIALOG_QUESTION, 30, 30)
 
         # Reset trayicon (default icon, default tooltip)
+        self.__current_pixbuf = None
+        self.__last_ratio = 1.0
         self.set_status()
 
         self.connect('activate', self.__on_left_click)
@@ -215,6 +218,8 @@
                 tooltip.append(self.format_episode_list(self.__finished_downloads, _('Finished downloads:')))
 
             self.set_status(self.STATUS_DOWNLOAD_IN_PROGRESS, ''.join(tooltip))
+            
+            self.progress_bar(float(percentage)/100.)
         else:
             self.__is_downloading = False
             self.__download_start_time = None
@@ -306,7 +311,8 @@
             else:
                 tooltip = 'gPodder - %s' % tooltip
             if self.__current_icon is not None:
-                self.set_from_pixbuf(self.__icon)
+                self.__current_pixbuf = self.__icon
+                self.set_from_pixbuf(self.__current_pixbuf)
                 self.__current_icon = None
         else:
             (status_tooltip, icon) = status
@@ -315,17 +321,26 @@
             else:
                 tooltip = 'gPodder - %s' % tooltip
             if self.__current_icon != icon:
-                self.set_from_pixbuf(self.__get_status_icon(icon))
+                self.__current_pixbuf = self.__get_status_icon(icon)
+                self.set_from_pixbuf(self.__current_pixbuf)
                 self.__current_icon = icon
         self.set_tooltip(tooltip)
 
     def format_episode_list(self, episode_list, caption=''):
-        """Format a list of episodes for tooltips and notifications
-        The parameter "episode_list" can either be a list containing
-        podcastItem objects or a list of strings.
+        """
+        Format a list of episodes for tooltips and notifications
+        Return a listing of episodes title separated by a line break.
+        Long title are troncated: "xxxx...xxxx"
+        If the list is too long, it is cut and the string "x others episodes" is append
+        
+        episode_list
+            can be either a list containing podcastItem objects 
+            or a list of strings of episode's title.
 
-        A formatted list of episodes is returned.
+        return
+            the formatted list of episodes as a string
         """
+        
         MAX_EPISODES = 10
         MAX_TITLE_LENGTH = 100
 
@@ -384,5 +399,26 @@
             self.send_notification(_('Your device has been updated by gPodder.'), _('Operation finished'))
         self.set_status()
         
+    def progress_bar(self, ratio):
+        """
+        draw a progress bar on top of the tray icon.
+        Be sure to call this method the first time with ratio=0
+        in order to initialise background image
+            
+        ratio
+            value between 0 and 1 (inclusive) indicating the ratio 
+            of the progress bar to be drawn
+                
+        """
 
+        # Only update in 3-percent-steps to save some resources
+        if abs(ratio-self.__last_ratio) < 0.03 and ratio > self.__last_ratio:
+            return
+
+        icon = self.__current_pixbuf.copy()
+        progressbar = draw.progressbar_pixbuf(icon.get_width(), icon.get_height(), ratio)
+        progressbar.composite(icon, 0, 0, icon.get_width(), icon.get_height(), 0, 0, 1, 1, gtk.gdk.INTERP_NEAREST, 255)
         
+        self.set_from_pixbuf(icon)
+        self.__last_ratio = ratio
+
Index: src/gpodder/draw.py
===================================================================
--- src/gpodder/draw.py	(revision 579)
+++ src/gpodder/draw.py	(working copy)
@@ -125,7 +125,14 @@
 
 
 def draw_pill_pixbuf(left_text, right_text):
-    s = draw_text_pill(left_text, right_text)
+    return cairo_surface_to_pixbuf(draw_text_pill(left_text, right_text))
+
+
+def cairo_surface_to_pixbuf(s):
+    """
+    Converts a Cairo surface to a Gtk Pixbuf by
+    encoding it as PNG and using the PixbufLoader.
+    """
     sio = StringIO.StringIO()
     try:
         s.write_to_png(sio)
@@ -144,3 +151,39 @@
     pixbuf = pbl.get_pixbuf()
     return pixbuf
 
+
+def progressbar_pixbuf(width, height, percentage):
+    COLOR_BG = (.4, .4, .4, .4)
+    COLOR_FG = (.2, .9, .2, 1.)
+    COLOR_FG_HIGH = (1., 1., 1., .5)
+    COLOR_BORDER = (0., 0., 0., 1.)
+
+    surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
+    ctx = cairo.Context(surface)
+
+    padding = int(float(width)/8.0)
+    bar_width = 2*padding
+    bar_height = height - 2*padding
+    bar_height_fill = bar_height*percentage
+
+    # Background
+    ctx.rectangle(padding, padding, bar_width, bar_height)
+    ctx.set_source_rgba(*COLOR_BG)
+    ctx.fill()
+
+    # Foreground
+    ctx.rectangle(padding, padding+bar_height-bar_height_fill, bar_width, bar_height_fill)
+    ctx.set_source_rgba(*COLOR_FG)
+    ctx.fill()
+    ctx.rectangle(padding+bar_width/3, padding+bar_height-bar_height_fill, bar_width/4, bar_height_fill)
+    ctx.set_source_rgba(*COLOR_FG_HIGH)
+    ctx.fill()
+
+    # Border
+    ctx.rectangle(padding-.5, padding-.5, bar_width+1, bar_height+1)
+    ctx.set_source_rgba(*COLOR_BORDER)
+    ctx.set_line_width(1.)
+    ctx.stroke()
+
+    return cairo_surface_to_pixbuf(surface)
+
Index: src/gpodder/services.py
===================================================================
--- src/gpodder/services.py	(revision 579)
+++ src/gpodder/services.py	(working copy)
@@ -142,9 +142,7 @@
             self.status_list[id]['iter'] = None
             self.status_list[id]['thread'].cancel()
             del self.status_list[id]
-            if self.has_items():
-                self.downloads_done_count += 1
-            else:
+            if not self.has_items():
                 # Reset the counter now
                 self.downloads_done_count = 0
         self.notify( 'list-changed')
@@ -184,6 +182,7 @@
     def download_completed(self, id):
         if id in self.status_list:
             self.notify('download-complete', self.status_list[id]['episode'])
+            self.downloads_done_count += 1
 
     def request_progress_detail( self, url):
         for status in self.status_list.values():
_______________________________________________
gpodder-devel mailing list
gpodder-devel@lists.berlios.de
https://lists.berlios.de/mailman/listinfo/gpodder-devel

Reply via email to