diff --git a/rigo/rigo/ui/gtk3/widgets/apptreeview.py b/rigo/rigo/ui/gtk3/widgets/apptreeview.py index 996366702..5f637a76c 100644 --- a/rigo/rigo/ui/gtk3/widgets/apptreeview.py +++ b/rigo/rigo/ui/gtk3/widgets/apptreeview.py @@ -20,6 +20,7 @@ this program; if not, write to the Free Software Foundation, Inc., """ from gi.repository import Gtk, Gdk, GObject import os +from threading import Timer from entropy.i18n import _ @@ -48,6 +49,12 @@ class AppTreeView(GenericTreeView): icon_size, store=None): Gtk.TreeView.__init__(self) + self._scrolling_timer = None + self._scrolled_view = None + self._scrolled_view_vadj = None + def _is_scrolling(): + return self._scrolling_timer is not None + self._entropy = entropy_client self._apc = apc self._service = rigo_service @@ -55,7 +62,8 @@ class AppTreeView(GenericTreeView): tr = CellRendererAppView(icons, self.create_pango_layout(""), show_ratings, - Icons.INSTALLED_OVERLAY) + Icons.INSTALLED_OVERLAY, + scrolling_cb=_is_scrolling) tr.set_pixbuf_width(icon_size) # create buttons and set initial strings @@ -105,6 +113,51 @@ class AppTreeView(GenericTreeView): self.set_search_equal_func(self._app_search, None) self.set_property("enable-search", True) + def _scrolling_event(self, vadj): + """ + Event received from the Gtk.VAdjustment of the + Gtk.ScrolledView containing this widget. + We expose the scrolling state to upper and lower layers. + """ + if self._scrolling_timer: + return + + def unset(): + # This may cause a race condition + # because an event of the past can + # reset the state right after scrolling_timer + # has been back set. But we don't really care in + # this case. We don't want to be *that* precise. + self._scrolling_timer = None + + def set_timer(): + t = Timer(1.0, unset) + t.name = "UnsetScrollingTimer" + t.daemon = True + return t + + t = self._scrolling_timer + if t is not None: + t.cancel() + + t = set_timer() + t.start() + self._scrolling_timer = t + + def set_scrolled_view(self, scrolled_view): + """ + Set the Gtk.ScrolledView container of this TreeView. + """ + vadj = scrolled_view.get_vadjustment() + vadj.connect("value-changed", self._scrolling_event) + self._scrolled_view = scrolled_view + self._scrolled_view_vadj = vadj + + def get_vadjustment(self): + sv = self._scrolled_view + if sv: + return sv.get_vadjustment() + def _row_activated_callback(self, path, rowref): self._apc.emit("application-activated", self.model.get_application(rowref)) diff --git a/rigo/rigo/ui/gtk3/widgets/cellrenderers.py b/rigo/rigo/ui/gtk3/widgets/cellrenderers.py index 09b79e544..78db031c9 100644 --- a/rigo/rigo/ui/gtk3/widgets/cellrenderers.py +++ b/rigo/rigo/ui/gtk3/widgets/cellrenderers.py @@ -21,9 +21,9 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """ -from gi.repository import Gtk, Gdk, GObject, Pango +from gi.repository import GLib, Gtk, Gdk, GObject, Pango -from threading import Lock +from threading import Lock, Timer from rigo.em import Ems from rigo.utils import escape_markup @@ -62,9 +62,17 @@ class CellRendererAppView(Gtk.CellRendererText): GObject.PARAM_READWRITE), } - def __init__(self, icons, layout, show_ratings, overlay_icon_name): + def __init__(self, icons, layout, show_ratings, + overlay_icon_name, scrolling_cb=None): super(CellRendererAppView, self).__init__() + self._is_scrolling = scrolling_cb + if scrolling_cb is None: + def _is_scrolling(): return False + self._is_scrolling = _is_scrolling + else: + self._is_scrolling = scrolling_cb + # geometry-state values self.pixbuf_width = 0 self.apptitle_width = 0 @@ -93,7 +101,6 @@ class CellRendererAppView(Gtk.CellRendererText): # icon not present in theme, probably because running uninstalled self._installed = icons.load_icon('emblem-system', self.OVERLAY_SIZE, 0) - return def _layout_get_pixel_width(self, layout): return layout.get_size()[0] / Pango.SCALE @@ -104,7 +111,7 @@ class CellRendererAppView(Gtk.CellRendererText): def _render_icon(self, cr, app, cell_area, xpad, ypad, is_rtl): # calc offsets so icon is nicely centered - icon = self.model.get_icon(app) + icon = self.model.get_icon(app, cached=self._is_scrolling()) xo = (self.pixbuf_width - icon.get_width())/2 if not is_rtl: @@ -142,11 +149,7 @@ class CellRendererAppView(Gtk.CellRendererText): max_layout_width = cell_area.width - self.pixbuf_width - 3*xpad - def _still_visible(): - return self.model.visible(app.get_details().pkg) - stats = app.get_review_stats(_still_visible_cb=_still_visible) - - if self.show_ratings and stats: + if self.show_ratings: max_layout_width -= star_width+6*xpad if self.props.isactive: @@ -187,7 +190,10 @@ class CellRendererAppView(Gtk.CellRendererText): def _still_visible(): return self.model.visible(app.get_details().pkg) - stats = app.get_review_stats(_still_visible_cb=_still_visible) + stats = app.get_review_stats( + _still_visible_cb=_still_visible, + cached=self._is_scrolling()) + if not stats: return sr = self._stars diff --git a/rigo/rigo_app.py b/rigo/rigo_app.py index 65bd48755..86631f10f 100644 --- a/rigo/rigo_app.py +++ b/rigo/rigo_app.py @@ -272,6 +272,7 @@ class Rigo(Gtk.Application): self._entropy, self._service, self._app_view_c, icons, True, AppListStore.ICON_SIZE, store=None) self._scrolled_view.add(self._view) + self._view.set_scrolled_view(self._scrolled_view) self._app_store = AppListStore( self._entropy, self._entropy_ws,