GtkIconView doesn't automatically fill the space with icon when user resizes the window

In the Ubuntu Accomplishments project we are having a few unusual bugs:

  • https://bugs.launchpad.net/bugs/986708
  • https://bugs.launchpad.net/bugs/974728

Namely that we have a window with a GtkNotebook and a GtkIconView on a page and another on another page.

When the user re-sizes the window the iconview does not automatically fill the space with icons (they stay in their original column layout) but if the user changes the GtkNotebook pages and thus refreshes the icon view the space is taken up as expected. How can we automatically use the space when resizing the window?

What is more concerning though is that when the window appears, we can resize it smaller - it seems as if the iconview is blocking us from resizing and then having a scrollable region for the icons.

The code looks like this. The ListStores that drive the IconViews:

    self.trophystore = Gtk.ListStore(str, GdkPixbuf.Pixbuf, bool, bool, str, str) # title, icon accomplished, locked, app, accomplishment
    self.trophystore.set_sort_column_id(COL_TITLE, Gtk.SortType.ASCENDING)
    self.trophy_icon.set_model(self.trophystore)

    self.oppstore = Gtk.ListStore(str, GdkPixbuf.Pixbuf, bool, bool, str, str) # title, icon, accomplished, locked, app, accomplishment
    self.oppstore.set_sort_column_id(COL_TITLE, Gtk.SortType.ASCENDING)
    self.opp_icon.set_model(self.oppstore)

    self.trophy_icon.set_text_column(COL_TITLE)
    self.trophy_icon.set_pixbuf_column(COL_PIXBUF)

    self.opp_icon.set_text_column(COL_TITLE)
    self.opp_icon.set_pixbuf_column(COL_PIXBUF)

Other than this, we don't really poke around with the IconViews, we just add content to the ListStores to update the views.

The code for the project is here - can anyone recommend how we can fix these two issues?


Solution 1:

Okay, as we have figure out how to fix this, I'll describe the solution here, in case anyone else has this problem.

The trick is to place the GtkIconView in a GtkScrolledWindow, and set it's hscrollbar_policy to "always". Then, a check-resize signal has to be used, to react when the user resizes the window (note that it must be checked if the size has changed, for the signal is emitted also when e.g. the window is dragged around).

When the size changes, the model used by GtkIconView has to be cleared and recreated, as this triggers GtkIconView properly reallocating the newly gained space (or shrinking). Also, as the result the horizontal scrollbar will never be seen, as the GtkIconView uses exactly that much space as the GtkScrolledWindow uses.

Solution 2:

My preferred solution to this problem is a very small subclass of Gtk.IconView:

class FluidIconView (Gtk.IconView):
    def __init__ (self):
        Gtk.IconView.__init__ (self)
        self.connect ("size-allocate", FluidIconView.on_size_allocate)

    def do_get_preferred_width (self):
        return (0,0)

    def on_size_allocate (self, allocation):
        [self.set_columns (m) for m in [1,self.get_columns ()]]

The get_preferred_width override allows the view to be arbitrarily narrow. The size-allocate callback forces a relayout by setting the number of columns to 1 and back.