[Gtk-sharp-list] Convenience method for creating windows

Federico Mena Quintero federico@ximian.com
Fri, 24 Sep 2004 12:50:45 -0500


Hi,

Right now, creating a Gdk.Window for a widget is a lot of work:

class MyWidget : Widget {
	protected override void OnRealized ()
	{
		WindowAttr attr;
		int attr_mask;

		base.OnRealized ();

		SetFlag (WidgetFlags.Realized);

		attr.WindowType = WindowType.Child;
		attr.X = Allocation.X;
		attr.Y = Allocation.Y;
		attr.Width = Allocation.Width;
		attr.Height = Allocation.Height;
		attr.Wclass = WindowClass.InputOutput;
		attr.Visual = Visual;
		attr.Colormap = Colormap;
		attr.EventMask = (Events |
				  EventMask.ExposureMask |
				  EventMask.ButtonPressMask |
				  EventMask.ButtonReleaseMask |
				  EventMask.PointerMotionMask |
				  EventMask.ScrollMask);

		attr_mask = (WindowAttributesType.X |
			     WindowAttributesType.Y |
			     WindowAttributesType.Visual |
			     WindowAttributesType.Colormap);

		GdkWindow = new Gdk.Window (ParentWindow, attr, attr_mask);
		GdkWindow.UserData = this.Handle;
	}
}

This is a lot of work, and has several flaky points:

1. Setting up the WindowAttr struct is painful, and you have to
coordinate it with the attr_mask.

2. You must remember to set the UserData of the window to
MyWidget.Handle; otherwise you won't get events from it.

Would it be good to have a convenience method for Widget:

namespace Gtk {
  public class Widget : ... {
    public Gdk.Window CreateSubwindow (Gdk.Window parent,
                                       int x, int y, 
                                       int width, int height,
                                       bool is_input_output,
                                       int extra_event_mask)
    {
            WindowAttr attr;
            int attr_mask;
            Gdk.Window window;

            if (parent == null)
                    throw new ArgumentNullException ("parent");

	    if (width < 1)
                    throw new ArgumentOutOfRangeException ("width", width, "must be greater than zero");

	    if (height < 1)
                    throw new ArgumentOutOfRangeException ("height", height, "must be greater than zero");

            attr_mask = WindowAttributesType.X | WindowAttributesType.Y;

            attr.WindowType = WindowType.Child;
            attr.X = x;
            attr.Y = y;
            attr.Width = width;
            attr.Height = height;
            attr.EventMask = this.Events | extra_event_mask;
            
            if (is_input_output) {
                    attr.Wclass = WindowClass.InputOutput;
                    attr.Visual = this.Visual;
                    attr.Colormap = this.Colormap;
                    attr_mask |= WindowAttributesType.Visual | WindowAttributesType.Colormap;
            } else
                    attr.Wclass = WindowClass.InputOnly;

            window = new Gdk.Window (parent, attr, attr_mask);
            window.UserData = this.Handle;

            return window;
    }
}

With that, writing a realize method would be as simple as this:

class MyWidget : Widget {
	protected override void OnRealized ()
	{
                base.OnRealized ();
		SetFlag (WidgetFlags.Realized);

		GdkWindow = CreateSubwindow (ParentWindow,
                                             Allocation.X, Allocation.Y,
                                             Allocation.Width, Allocation.Height,
                                             true,
                                             (EventMask.ExposureMask |
                                              EventMask.ButtonPressMask |
				              EventMask.ButtonReleaseMask |
				              EventMask.PointerMotionMask |
				              EventMask.ScrollMask));
	}
}

If one needs to do exotic stuff like using a different visual/colormap,
or a non-default cursor, one can create the window by hand.

What do people think?  Would this be a useful addition?

  Federico