Native GTK2 D Bindings

Artur Skawina art.08.09 at gmail.com
Tue Jan 24 12:47:47 PST 2012


On 01/24/12 21:03, Jacob Carlborg wrote:
> On 2012-01-24 17:09, Artur Skawina wrote:
>> On 01/24/12 12:15, Kagamin wrote:
>>> On Sunday, 22 January 2012 at 21:56:24 UTC, Artur Skawina wrote:
>>>>
>>>>
>>>>                   Native GTK2 bindings for D.
>>>>
>>>>
>>>> "Native" for two reasons:
>>>>
>>>> 1. Uses the C API directly. No class wrappers and no function wrappers.
>>>> 2. OO interface, giving a native D look and feel.
>>>
>>> Once again. Is it direct C bindings OR OO interface OR both?
>>
>> Both.
>>
>> There are basically three parts:
>>
>> 1) data type definitions - ie structs, aliases (typedefs), and enums (constants)
>> 2) C prototypes; this, plus (1) above, let's you use the C API directly
>> 3) "methods", which are actually disguised GTK functions.
>>
>> An example:
>>
>> struct Rectangle {
>>     int x, y, width, height;
>>
>>     // Calculates the intersection of two rectangles. It is allowed for
>>     // do not intersect, @dest's width and height is set to 0 and its x
>>     // and y values are undefined. If you are only interested in whether
>>     // the rectangles intersect, but not in the intersecting area itself,
>>     // pass %NULL for @dest.
>>     // RETURNS: %TRUE if the rectangles intersect.
>>     //<src2>: a #GdkRectangle
>>     //<dest>: return location for the intersection of @src1 and @src2, or %NULL
>>     int intersect(Rectangle* src2, /*out*/ Rectangle* dest=null) {
>>        return gdk_rectangle_intersect(&this, src2, dest);
>>     }
>>
>>     // Calculates the union of two rectangles.
>>     // The union of rectangles @src1 and @src2 is the smallest rectangle which
>>     // includes both @src1 and @src2 within it.
>>     // It is allowed for @dest to be the same as either @src1 or @src2.
>>     //<src2>: a #GdkRectangle
>>     //<dest>: return location for the union of @src1 and @src2
>>     void union_(Rectangle* src2, /*out*/ Rectangle* dest) {
>>        gdk_rectangle_union(&this, src2, dest);
>>     }
>> }
>>
>> So instead of:
>>
>>> gdk_rectangle_union(&dirtyRect,&event.area,&dirtyRect);
>>
>> you can write:
>>
>>> dirtyRect.union_(&event.area,&dirtyRect);
>>
>> and, once i add the (forgotten) overload:
>>
>>> dirtyRect.union_(&event.area);
>>
>> and all of these will result in identical code being emitted.
>>
>>
>> All of the gtk2/*.d files are browsable online:
>> http://repo.or.cz/w/girtod.git/tree/refs/heads/gtk2:/gtk2
>>
>>
>> And, yes, this is probably suitable for Deimos, iff part #3 is.
>> (I see no advantage in splitting out the trivial "methods")
>>
>> artur
> 
> So what's the difference compared to gtkD:

The simple struct above maps to this *module* in gtkD:

(i've stripped some comments and whitespace)
-------------------------------------------------------
module gdk.Rectangle;

public  import gtkc.gdktypes;

private import gtkc.gdk;
private import glib.ConstructionException;

public class Rectangle
{
	/** the main Gtk struct */
	protected GdkRectangle* gdkRectangle;
	
	public GdkRectangle* getRectangleStruct()
	{
		return gdkRectangle;
	}
	
	/** the main Gtk struct as a void* */
	protected void* getStruct()
	{
		return cast(void*)gdkRectangle;
	}
	
	/**
	 * Sets our main struct and passes it to the parent class
	 */
	public this (GdkRectangle* gdkRectangle)
	{
		if(gdkRectangle is null)
		{
			this = null;
			return;
		}
		this.gdkRectangle = gdkRectangle;
	}
	
	/**
	 * Calculates the intersection of two rectangles. It is allowed for
	 * dest to be the same as either src1 or src2. If the rectangles
	 * do not intersect, dest's width and height is set to 0 and its x
	 * and y values are undefined. If you are only interested in whether
	 * the rectangles intersect, but not in the intersecting area itself,
	 * pass NULL for dest.
	 * Params:
	 * src2 = a GdkRectangle
	 * dest = return location for the
	 * intersection of src1 and src2, or NULL. [out caller-allocates][allow-none caller-allocates]
	 * Returns: TRUE if the rectangles intersect.
	 */
	public int intersect(Rectangle src2, Rectangle dest)
	{
		return gdk_rectangle_intersect(gdkRectangle, (src2 is null) ? null : src2.getRectangleStruct(), (dest is null) ? null : dest.getRectangleStruct());
	}
	
	/**
	 * Calculates the union of two rectangles.
	 * The union of rectangles src1 and src2 is the smallest rectangle which
	 * includes both src1 and src2 within it.
	 * It is allowed for dest to be the same as either src1 or src2.
	 * Params:
	 * src2 = a GdkRectangle
	 * dest = return location for the union of src1 and src2
	 */
	public void unio(Rectangle src2, Rectangle dest)
	{
		gdk_rectangle_union(gdkRectangle, (src2 is null) ? null : src2.getRectangleStruct(), (dest is null) ? null : dest.getRectangleStruct());
	}
}
-------------------------------------------------------------

Now, imagine how eg simple exposure compression code looks like,
using both approaches... Where you have one Rectangle storing the
area that needs to be repainted, and receive several events, all 
of them with another embedded Rectangle struct containing newly
damaged regions.. Hint: the gtkD approach gives you no way to
directly use the gdkRectangle structs passed - you need to allocate
a new class instance for every single one of them.

Using my bindings, that same code is just:

> dirtyRect.union_(&event.area);

And this is just a simple example.


gtkD also does some other silly things, like adds another level
of indirection, by not linking against the GTK libs, but manually
trying to load them, dlopen-style. Failing and/or scaring the user
at runtime if it finds a version it didn't expect.

There are probably more issues, but i didn't look at gtkD closely,
after being bitten by the latter and realizing the former.

D makes it possible to map most of the API 1:1 completely for free,
why would anyone want to use a middle layer that adds almost no
value, but a significant cost? (think GC; the code overhead wouldn't
really be noticeable in most cases, yes)

artur


More information about the Digitalmars-d-announce mailing list