Problem solving

Problem solving

During the last couple of days, I’ve stumbled upon a few problems that I thought might be worth writing a bit about, so that people can eventually Google it.

Height-for-width size negotiation with GTK+ 2

I am in the process of writing a new library interface for logdiag, inspired by Microsoft Visio. The idea is that there will be a pane on the side of the main window showing various electronic symbols in several categories.

When displaying a category of symbols, what I am trying to do is to fit as many of them as possible into the horizontal space the widget is given by its parent. The result of the algorithm that accomplishes this task is the required height to show them all without clipping.

This doesn’t go well with the size negotiation model used in GTK+ 2, though, as it constitutes from only two steps: first you request a minimum size, and then you simply receive the dimensions of the area your parent widget was able to provide you. This problem is solved in the next major revision of GTK+, but as I haven’t yet rewritten my code for it because I’m still waiting for a proper Win32 bundle release, I was rather searching for any simple hack that would give satisfying results.

While original GTK+ widgets use all sorts of sorcery involving private variables in order to solve this, I’ve eventually found an easier way around. And it’s kind of trivial indeed.

struct MyWidgetPrivate {
    guint height_negotiation : 1;
};

static void on_size_request (MyWidget *self, GtkRequisition *requisition) {
    requisition->width = MY_WIDGET_HORIZONTAL_MINIMUM;

    if (self->priv->height_negotiation) {
        GtkAllocation alloc;
        gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
        requisition->height = compute_height_for_width (self, alloc.width);
    } else
        requisition->height = MY_WIDGET_VERTICAL_MINIMUM;
}

static void on_size_allocate (MyWidget *self, GdkRectangle *allocation) {
    if (self->priv->height_negotiation)
        self->priv->height_negotiation = FALSE;
    else {
        self->priv->height_negotiation = TRUE;
        gtk_widget_queue_resize (GTK_WIDGET (self));
    }
}

Basically it just adds another stage to the negotiation. When asked first, it returns what it’s supposed to (the minimum size of a single symbol in my case), but when it receives the actual allocation, it goes one step back and says ‘Well, forget that, while I do want to have that width, I can’t allow myself to be any shorter than this new value’. It assumes that it’s going to get the same width as before, and it most probably is. If you put the actual width into the second request, the widget would stop having its size renegotiated when the containing widget becomes narrower than that.

OpenSSH and SOCKS 5

When I was toying around with my useless library, something snapped in me and I ended up finally finishing the almost-complete SOCKS 5 module. Though when I got to testing if it works as expected, it wouldn’t want to connect to anything.

The reason was that OpenSSH always returns an invalid address to connect to: INADDR_ANY, port number 0. I even checked the sources. It’s there, hardcoded. Instead, what you’re supposed to do, is to continue using the very same socket via which you’ve successfully negotiated the connection.

I believe this behaviour is in conflict with the specification. But I can see what stands behind this. This is exactly how it was done in SOCKS 4.

Mouse and ncurses

It just doesn’t work together. Don’t ask me why. I’ve been trying all I could to get all the events properly from the damned library but the only reliable thing was BUTTON1_PRESSED. I’m not sure if this is specific to Ubuntu/Debian but since it’s one of the most popular distributions, if you want to get xterm mouse events from the terminal, you’ll have to find some other way to do it. VIM handles it all on its own, and I haven’t noticed any major problem with it.

Note from the future: this has been fixed at some point.