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