1

I'm trying to make a custom GTK widget in Vala, but I'm already failing at the very first basic attempt, so I'd like some help in knowing where I'm going wrong. I feel like I must be missing something painstakingly obvious, but I just can't see it.

I have three files with the following contents:

start.vala:

using Gtk;

namespace WTF
{
        MainWindow main_window;

        int main(string[] args)
        {
                Gtk.init(ref args);
                main_window = new MainWindow();
                Gtk.main();
                return 0;
        }
}

main_window.vala:

using Gtk;

namespace WTF
{
        public class MainWindow : Window
        {
                public MainWindow()
                {
                        /* */
                        Entry entry = new Entry();
                        entry.set_text("Yo!");
                        this.add(entry);
                        /* */

                        /* 
                        CustomWidget cw = new CustomWidget();
                        this.add(cw);
                        /* */

                        this.window_position = WindowPosition.CENTER;
                        this.set_default_size(400, 200);
                        this.destroy.connect(Gtk.main_quit);

                        this.show_all();
                }
        }
}

custom_widget.vala:

using Gtk;

namespace WTF
{
        public class CustomWidget : Bin
        {
                public CustomWidget()
                {
                        Entry entry = new Entry();
                        entry.set_text("Yo");
                        this.add(entry);
                        this.show_all();
                }
        }
}

As you can see, in main_window.vala, I have two sets of code. One that adds the Entry widget directly, and one that adds my custom widget. If you run the one that adds the Entry widget directly, you get this result:

functioning widget

If you run the one with the custom widget, however, you get this result:

malfunctioning widget

Just for the record, this is the complication command I use:

valac --pkg gtk+-2.0 start.vala main_window.vala custom_widget.vala -o wtf

EDIT:

Following user4815162342's suggestion, I implemented the size_allocate method on my custom Bin widget, like so:

public override void size_allocate(Gdk.Rectangle r)
{
        stdout.printf("Size_allocate: %d,%d ; %d,%d\n", r.x, r.y, r.width, r.height);
        Allocation a = Allocation() { x = r.x, y = r.y, width = r.width, height = r.height };
        this.set_allocation(a);

        stdout.printf("\tHas child: %s\n", this.child != null ? "true" : "false");
        if (this.child != null)
        {
                int border_width = (int)this.border_width;
                Gdk.Rectangle cr = Gdk.Rectangle()
                {
                        x = r.x + border_width,
                        y = r.y + border_width,
                        width = r.width - 2 * border_width,
                        height = r.height - 2 * border_width
                };
                stdout.printf("\tChild size allocate: %d,%d ; %d, %d\n", cr.x, cr.y, cr.width, cr.height);
                this.child.size_allocate(cr);
        }
}

It writes the following in the console:

Size_allocate: 0,0 ; 400,200
        Has child: true
        Child size allocate: 0,0 ; 400, 200

And the window renders thusly:

partially functioning widget

Alex
  • 3,429
  • 4
  • 36
  • 66

1 Answers1

2

GtkBin is an abstract single-child container, typically intended to decorate the child widget in some way, or change its visibility or size. Without some added value, a single-child container would be indistinguishable from the widget it contains and therefore not very useful.

Since GtkBin doesn't know what kind of decorations you will draw around the child, it expects you to implement your own size_allocate. A simple implementation is available in gtk_event_area_size_allocate, a more complex one in gtk_button_size_allocate.

This answer shows a minimal size_allocate implementation in PyGTK which should be straightforward to port to Vala. If you do anything more complex than that, you will need to also implement expose, and possibly other methods, but this will get you started.

Community
  • 1
  • 1
user4815162342
  • 141,790
  • 18
  • 296
  • 355
  • Thanks, I was completely unaware that the GtkBin widget was unhelpful as a general purpose container on its own. Based on what you said, I decided to inherit from GtkEventBox instead, and there everything seems to work just splendidly. I tried implementing the minimal size_allocate from your link in Vala, but it didn't turn out so well, heh. – Alex Apr 07 '13 at 10:43
  • 2
    @Alex That you cannot instantiate it is somewhat of a giveaway. :) `GtkEventBox` provides a more gentle introduction, but it does carry some additional functionality that you don't need. It also forces a GDK window for the container, which is a waste if not needed. Once you get more proficient with the low-level workings of widgets, you might want to get back to `GtkBin`. – user4815162342 Apr 07 '13 at 11:28
  • Yeah, I might give it a try at some later point... it was kind of disappointing not to manage to implement the size_allocate. I'm 99% certain I did exactly what the Python version did, but when my version rendered, all I saw rendered was a thin line instead of the entry text box. – Alex Apr 08 '13 at 09:04
  • @Alex Have you tried to add some prints that would help you debug what was going wrong? – user4815162342 Apr 08 '13 at 09:27
  • Yeah, and nothing seemed wrong with the values I was working with... the numbers were sensible, and I basically just set them on myself (with set_allocation(...)) and then passed them on to the child widget (with child.size_allocate(...)), but like I said, it ended up just rendering a line for some reason... (I did include the border_width calculations as well, though those numbers were all 0, so it didn't actually change the size of the allocation.) I'll edit my question to include that code, and you can take a look. – Alex Apr 08 '13 at 09:54
  • @Alex Why not start a separate question for the `GtkBin.size_allocate` issue? – user4815162342 Apr 08 '13 at 11:11