Indice

resize tweaks

First: the method gtk.Window.resize() doesnt't work with a single argument (setting the other to -1, as instead does gtk.Widget.set_size_request()). OK, this is documented, though ugly.

Now: if a gtk.Window w has size (100,100) and we run the following code:

w.resize(200,200)
size = w.get_size()
w.resize(*size)

, then the window won't resize to 200,200, but to 100,100. In fact “resize” doesn't really resize, it just queues a resize process, while if we use get_size we get the current size, not the queued one. This means if several functions try to resize (and it makes sense, if each one takes care of a single dimension), we have race conditions.

I solved that (both problems) with the following functions:

def unset_real_size(window, event):
    """Fields 'real width' and 'real height' become obsolete (or at least
    useless) when a resize actually takes place.
    """

    window.set_data('real width', None)
    window.set_data('real height', None)
    
    handler = window.get_data('configure handler')
    if handler:
        # The callback is now useless; remove it.
        window.disconnect(handler)
        window.set_data('configure handler', None)
    
def ensure_configure_handler(window):
    """Ensure that unset_real_size is called.
    """
    if not window.get_data('configure handler'):
        new_handler = window.connect('configure-event', unset_real_size)
        window.set_data('configure handler', new_handler)

def get_width(window):
    width = window.get_data('real width')
    if not width:
        width = window.get_size()[0]
    return width

def get_height(window):
    height = window.get_data('real height')
    if not height:
        height = window.get_size()[1]
    return height

def set_width(window, width):
    ensure_configure_handler(window)

    window.set_data('real width', width)
    height = get_height(window)        
    window.resize(width, height)
  
def set_height(window, height):
    ensure_configure_handler(window)

    window.set_data('real height', height)
    width = get_width(window)        
    window.resize(width, height)

set_size_request

Notice that set_size_request has a similar problem: if a gtk.Widget widget's get_size_request gives (-1,-1) and I run the following code:

widget.set_size_request(100,100)
widget.set_size_request(-1, -1)

, it won't expand at all, nothing will happen. This is an issue if you wanted to use this as a hack to resize the widget but let to the user the possibility to shrink it again; an hackish way to solve this is instead the following code:

widget.set_size_request(100,100)
gobject.idle_add(widget.set_size_request, -1, -1)

gtk.ScrolledWindow

While gtk.Containers usually propagate size requests from child(ren) to parent, gtk.ScrolledWindow doesn't; instead, it sets a predefined (hardcoded, presumably) size. Apparently, this makes sense: if you want the whole widget shown, why a ScrolledWindow?! However, there are 2 situations in which this is hateful:

I solved this with the following code (widget is the widget we want to resize so that it is fully shown), thanks to owen in freenode.irc's #gtk+ for the hint:

  
    scrolledwindows = []
    scrolledwindows_policies = []
    scrolledwindows_hscrollbars = []
  
    while widget:
        # The ScrolledWindows stop propagation of queue_redraws, unless they
        # have the scrollbars disabled, so here we disable them...
        if gobject.type_is_a(widget, gtk.ScrolledWindow):
            scrolledwindows.append(widget)
            scrolledwindows_policies.append(widget.get_policy())
            widget.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER)
            scrolledwindows_hscrollbars.append(widget.get_hscrollbar())
        widget = widget.get_parent()

    toplevel = treeview.get_toplevel()

    # ... then we can take the size...

    new_width = toplevel.size_request()[0]

    # ... add the size of bars...
    bars_width = 0
    for index in range(len(scrolledwindows)):
        # (not needed if the policy hides it)
        if scrolledwindows_policies[index][0] == gtk.POLICY_ALWAYS:
            bars_width += scrolledwindows_hscrollbars[index].size_request()[0]
        scrolledwindows[index].set_policy(*scrolledwindows_policies[index])
#    print "width:", new_width

    # ... and put together the total size.

    new_width += bars_width