digitalmars.D.announce - Native GTK2 D Bindings
- Artur Skawina (41/41) Jan 22 2012 Native GTK2 bindings for D.
- Walter Bright (4/7) Jan 22 2012 This makes me suspect that part of this would be an ideal candidate for
- Trass3r (2/3) Jan 22 2012 gdc does cross module inlining if you pass all modules to it at once.
- Artur Skawina (10/13) Jan 22 2012 No. I named it "native" for a reason. The method names are not manipulat...
- Trass3r (2/9) Jan 22 2012 No, in there you claim gdc didn't support cross module inlining.
- Trass3r (2/3) Jan 22 2012 Or at least it suggests that:
- Artur Skawina (12/27) Jan 22 2012 Well, it would be a trivial addition. I'd just like to avoid having
- bearophile (11/17) Jan 22 2012 The convention for D classes/structs/enums is CamelCase, while functions...
- Artur Skawina (34/53) Jan 22 2012 There is no such thing as a language mandated identifier naming conventi...
- Trass3r (4/10) Jan 23 2012 I think there was a thread recently which described a way to get ahold o...
- bearophile (7/16) Jan 23 2012 It's an example of code where named arguments are useful for the person ...
- Timon Gehr (5/22) Jan 23 2012 This is wrong. String literals are meant to allow a cast to a pointer.
- Gour (12/20) Jan 23 2012 It is very nice to see that the GUI world of D is moving forward!
- Kagamin (2/7) Jan 24 2012 Once again. Is it direct C bindings OR OO interface OR both?
- Artur Skawina (39/54) Jan 24 2012 Both.
- Jacob Carlborg (5/59) Jan 24 2012 So what's the difference compared to gtkD:
- Gour (10/11) Jan 24 2012 I believe it was already mentioned: NIH syndrome. ;)
- Artur Skawina (90/167) Jan 24 2012 The simple struct above maps to this *module* in gtkD:
- Kagamin (16/23) Jan 28 2012 For some reason
- Artur Skawina (23/41) Jan 28 2012 Wrapping one struct in another, with no extra fields, shouldn't
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. The code generated when using these bindings is identical to the equivalent C version. Bit-for-bit, there is zero overhead. [1] BINDINGS The D modules in this package give access to: GLib-2.0 GModule-2.0 GObject-2.0 Gio-2.0 GdkPixbuf-2.0 Pango-1.0 Gdk-2.0 Atk-1.0 Gtk-2.0 There is also a minimal <cairo-1.0> stub, which only allows the GTK stack to build, but isn't really usable. [...more info in the README.txt file...] --------------------------------------------------------------------------------- This is a *very* early release. Works for me (tm), but i've only tried the basic functionality so far. I don't know how much time I'll be able to spend on this in the next days and as it's already in a usable state. maybe somebody else wants to play with it already. At this point i'm mostly interested in API related thoughts -- i'd like to get it right *before* adding GTK3 support. The code is available at http://repo.or.cz/w/girtod.git The bindings are in the "gtk2" branch; the "master" branch has the tool used to generate all the gtk2/*.d modules, some examples and a README. Yes, there's even a section in there on "Why?" and the answer isn't NIH. :) The gtk2 package (from the "gtk2" branch) can be used as-is, but if you'd like to play with (re-)generating the bindings: - The makefile is just an example of how to use the thing. It's GDC specific, x86 specific; the "configure" machinery still needs to be done. But it should be functional enough to rebuild the gtk2/*.d modules, with a few local tweaks. Which can then be moved and used in your application directly (place them in a "gtk2" subdirectory). - See ./buildem for how to build the bindings. artur
Jan 22 2012
On 1/22/2012 1:54 PM, 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.This makes me suspect that part of this would be an ideal candidate for inclusion in the Deimos project: https://github.com/D-Programming-Deimos/
Jan 22 2012
The function names should be converted to camelCase.and a README.gdc does cross module inlining if you pass all modules to it at once.
Jan 22 2012
On 01/23/12 00:16, Trass3r wrote:The function names should be converted to camelCase.No. I named it "native" for a reason. The method names are not manipulated in any way - they come directly from GTK. I could *add* all kind of aliases, including camelCased ones, but why would anyone want to use those?gdc does cross module inlining if you pass all modules to it at once.As i mentioned in the README; but that's not really a solution. For me, LTO works for all apps using these bindings, but i added that footnote so that i could write "zero-cost" and not have people complain that the calls are not going directly to the PLT (as they do in C). :) artur
Jan 22 2012
No. I named it "native" for a reason. The method names are not manipulated in any way - they come directly from GTK. I could *add* all kind of aliases, including camelCased ones, but why would anyone want to use those?Cause those C names with underscores are just crappy.No, in there you claim gdc didn't support cross module inlining.gdc does cross module inlining if you pass all modules to it at once.As i mentioned in the README; but that's not really a solution.
Jan 22 2012
No, in there you claim gdc didn't support cross module inlining.Or at least it suggests that: "As long as GDC cross module inlining doesn't work"
Jan 22 2012
On 01/23/12 00:52, Trass3r wrote:Well, it would be a trivial addition. I'd just like to avoid having several conventions around, unless necessary. I'd be more interested in comments on how to make the code using these bindings cleaner (the other meaning of "native" is "as-close- -to-natural-D-as-possible"). So far, a sample D GTK app looks like this: http://repo.or.cz/w/girtod.git/blob/refs/heads/master:/example_gtk3.d Anything I could change API-wise to improve things, that doesn't require language changes?No. I named it "native" for a reason. The method names are not manipulated in any way - they come directly from GTK. I could *add* all kind of aliases, including camelCased ones, but why would anyone want to use those?Cause those C names with underscores are just crappy.No, in there you claim gdc didn't support cross module inlining.gdc does cross module inlining if you pass all modules to it at once.As i mentioned in the README; but that's not really a solution.From the README: (apparently, another workaround is to build all the *.d files together; I've never tried this)It's a workaround, not a solution. artur
Jan 22 2012
Artur Skawina:So far, a sample D GTK app looks like this: http://repo.or.cz/w/girtod.git/blob/refs/heads/master:/example_gtk3.d Anything I could change API-wise to improve things, that doesn't require language changes?The convention for D classes/structs/enums is CamelCase, while functions and methods are the same but start with a lowercase. This line of code seems an example for people that like named arguments in D: gtk.init(null,null); Such lines of code contains a bad cast: set_title(cast(char*)"Hello World!"); but.signal_connect!"button-press-event"(&bpress_cb, cast(void*)label); I think toStringz shouldn't return a const pointer: str0 = cast(char*)toStringz(display_string); Bye, bearophile
Jan 22 2012
On 01/23/12 03:17, bearophile wrote:Artur Skawina:There is no such thing as a language mandated identifier naming convention. If you think otherwise - make the compiler enforce it. :)So far, a sample D GTK app looks like this: http://repo.or.cz/w/girtod.git/blob/refs/heads/master:/example_gtk3.d Anything I could change API-wise to improve things, that doesn't require language changes?The convention for D classes/structs/enums is CamelCase, while functions and methods are the same but start with a lowercase.This line of code seems an example for people that like named arguments in D: gtk.init(null,null);This has nothing to do with named arguments, it's gtk wanting to parse and modify the C argv[], which i didn't want to rebuild in these examples. /* void gtk_init(/*inout*/ int* argc, /*inout*/ char*** argv=null);*/ A function which handles the argv conversion both ways would be a good idea. On the list. Thanks.Such lines of code contains a bad cast: set_title(cast(char*)"Hello World!");If you had seen the glib code i was initially testing with... :) Unfortunately the immutable-strings don't mix well with non-D APIs, especially, like in this case, when practically all const annotations are lost in translation (the GIR files are already missing them). Initially, i wanted to add a cstring type which would handle all the casts and zero-termination transparently, but then decided to see how things will work without that kind of magic. Not only would most strings have to be duped, but an extra reference to the copies would be needed, in case the string escaped. Requiring explicit casts for most strings is ugly, but not something that can be fixed both safely and cheaply. For a GUI toolkit the amount of casts needed may be acceptable. [1] I did remove the glib-using code from the repo because it made D look bad...but.signal_connect!"button-press-event"(&bpress_cb, cast(void*)label);Here <label> is really an opaque (void*) that gets passed to the callback. I don't see a way to get rid of the cast, while improving type safety...I think toStringz shouldn't return a const pointer: str0 = cast(char*)toStringz(display_string);(immutable(char)*) C APIs are not exactly common. :) IOW i think you're right.Bye, bearophileThanks, artur [1] Yes, this *will* cause bugs. But what's the alternative? A strongly typed C-string type would help catching most non-zero-terminated strings, but would need casts too (eg when initialized from literals) and still not help with the escaping references (libraries keeping the pointer around internally).
Jan 22 2012
It's not mandated, it's standard. http://www.d-programming-language.org/dstyle.htmlThe convention for D classes/structs/enums is CamelCase, while functions and methods are the same but start with a lowercase.There is no such thing as a language mandated identifier naming convention.A function which handles the argv conversion both ways would be a good idea. On the list. Thanks.I think there was a thread recently which described a way to get ahold of argv.
Jan 23 2012
Artur Skawina:There is no such thing as a language mandated identifier naming convention. If you think otherwise - make the compiler enforce it. :)There is a D style guide.It's an example of code where named arguments are useful for the person that reads the code to know what those two arguments are :-)This line of code seems an example for people that like named arguments in D: gtk.init(null,null);This has nothing to do with named arguments,Requiring explicit casts for most strings is ugly, but not something that can be fixed both safely and cheaply. For a GUI toolkit the amount of casts needed may be acceptable. [1]But a string is like a 2-tuple, it's not a pointer. It's not meant to allow a cast to pointer. So it's better to cast the ".ptr" of an array: cast(char*)"Hello World!".ptr Bye, bearophile
Jan 23 2012
On 01/24/2012 12:18 AM, bearophile wrote:Artur Skawina:This is wrong. String literals are meant to allow a cast to a pointer. String literals *implicitly* convert to immutable(char)*. They are designed to simultaneously be D style strings and C style strings. There is really no need for that .ptr there. It is just noise.There is no such thing as a language mandated identifier naming convention. If you think otherwise - make the compiler enforce it. :)There is a D style guide.It's an example of code where named arguments are useful for the person that reads the code to know what those two arguments are :-)This line of code seems an example for people that like named arguments in D: gtk.init(null,null);This has nothing to do with named arguments,Requiring explicit casts for most strings is ugly, but not something that can be fixed both safely and cheaply. For a GUI toolkit the amount of casts needed may be acceptable. [1]But a string is like a 2-tuple, it's not a pointer. It's not meant to allow a cast to pointer. So it's better to cast the ".ptr" of an array: cast(char*)"Hello World!".ptr Bye, bearophile
Jan 23 2012
On Sun, 22 Jan 2012 22:54:03 +0100 Artur Skawina <art.08.09 gmail.com> wrote:1. Uses the C API directly. No class wrappers and no function wrappers. 2. OO interface, giving a native D look and feel. =20 =20 The code generated when using these bindings is identical to theequivalent C version. Bit-for-bit, there is zero overhead. [1]It is very nice to see that the GUI world of D is moving forward!Yes, there's even a section in there on "Why?" and the answer isn't NIH. :)...although it would be nice to save breadth and work together. Hopefully your project will stay maintained and developed further. Sincerely, Gour --=20 In the material world, one who is unaffected by whatever good=20 or evil he may obtain, neither praising it nor despising it,=20 is firmly fixed in perfect knowledge. http://atmarama.net | Hlapicina (Croatia) | GPG: 52B5C810
Jan 23 2012
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?
Jan 24 2012
On 01/24/12 12:15, Kagamin wrote:On Sunday, 22 January 2012 at 21:56:24 UTC, Artur Skawina wrote: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: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?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 (I see no advantage in splitting out the trivial "methods") artur
Jan 24 2012
On 2012-01-24 17:09, Artur Skawina wrote:On 01/24/12 12:15, Kagamin wrote:So what's the difference compared to gtkD: http://dsource.org/projects/gtkd -- /Jacob CarlborgOn Sunday, 22 January 2012 at 21:56:24 UTC, Artur Skawina wrote: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: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?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 (I see no advantage in splitting out the trivial "methods") artur
Jan 24 2012
On Tue, 24 Jan 2012 21:03:22 +0100 Jacob Carlborg <doob me.com> wrote:So what's the difference compared to gtkD:I believe it was already mentioned: NIH syndrome. ;) Sincerely, Gour --=20 Those persons who execute their duties according to My injunctions=20 and who follow this teaching faithfully, without envy, become free=20 from the bondage of fruitive actions. http://atmarama.net | Hlapicina (Croatia) | GPG: 52B5C810
Jan 24 2012
On 01/24/12 21:03, Jacob Carlborg wrote:On 2012-01-24 17:09, Artur Skawina wrote: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:On 01/24/12 12:15, Kagamin wrote:So what's the difference compared to gtkD:On Sunday, 22 January 2012 at 21:56:24 UTC, Artur Skawina wrote: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: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?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 (I see no advantage in splitting out the trivial "methods") arturdirtyRect.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
Jan 24 2012
On Tuesday, 24 January 2012 at 16:09:21 UTC, Artur Skawina wrote:So instead of:For some reason gdk_rectangle_union(&dirtyRect, &event.area, &dirtyRect); looks better.gdk_rectangle_union(&dirtyRect, &event.area, &dirtyRect);you can write:dirtyRect.union_(&event.area, &dirtyRect);and all of these will result in identical code being emitted.what if struct Rectangle { GdkRectangle r; alias r this; ... methods ... } Will a different code be emitted? Will alias this work with C api?(I see no advantage in splitting out the trivial "methods")C bindings are a value on their own, this is probably why deimos users(libraries) of the bindings.
Jan 28 2012
On 01/28/12 17:28, Kagamin wrote:On Tuesday, 24 January 2012 at 16:09:21 UTC, Artur Skawina wrote:Wrapping one struct in another, with no extra fields, shouldn't make any difference wrt the resulting code. But i don't see any reason to do it like that, and, in addition to having two not 100% compatible ways to refer to the same thing, it would make some things harder and/or impossible. Things like the pseudo struct inheritance magic (you can call methods present in *parent* objects and the right thing will happen; the Rectangle is not a good example for this, see the AppwWin struct in example_gtk3.d, where eg. the last "add()" actually is a GtkContainer method, not a GtkWindow one) and implicit conversions [1]. alias-this makes no difference for the C API, it only matters when you use the D extras.and all of these will result in identical code being emitted.what if struct Rectangle { GdkRectangle r; alias r this; ... methods ... } Will a different code be emitted? Will alias this work with C api?The problem with splitting out the methods is that it would create another module. As it is, an app only needs to "import gtk2.gtk2;" and everything works. Having some apps use this and others use eg a "gtk2.gtkd2" would be bad. Having different identifiers (like the suggested camelCased ones) would be even worse. Let's reduce the pointless balkanization, not encourage it. artur [1] D needs a way to control all implicit conversions for structs/classes, both *if* these should happen and *how*. Also *all* casts should be properly lowered, right now you have to eg use alias-this tricks to catch implicit casts.(I see no advantage in splitting out the trivial "methods")C bindings are a value on their own, this is probably why deimos doesn't like
Jan 28 2012