Monday, November 12, 2007

IOChannels and Spawning

For the most part, we like to avoid wrapping as much of glib as possible, instead preferring the .Net framework capabilities. We hide as many GList and GHashtable parameters as possible, for example.

I've received several comments in the past that the .Net APIs for IO and process spawning didn't really match up to the glib API. Taking this feedback, I spent the last couple days wrapping, testing, and documenting a new glib-sharp binding for g_spawn_* and GIOChannel.

Here's an example usage from the docs:

using GLib;
using System;

public class SpawnTest {

public static void Main (string[] args)
{
new SpawnTest ();
}

MainLoop main_loop;
IOChannel channel;

public SpawnTest ()
{
main_loop = new MainLoop ();

try {
Process proc;
int stdin = Process.IgnorePipe;
int stdout = Process.RequestPipe;
int stderr = Process.IgnorePipe;
GLib.Process.SpawnAsyncWithPipes (null, new string[] {"pwd"}, null,
SpawnFlags.SearchPath, null,
out proc, ref stdin, ref stdout,
ref stderr);
channel = new IOChannel (stdout);
channel.AddWatch (0, IOCondition.In | IOCondition.Hup, new IOFunc (ReadStdout));
} catch (Exception e) {
Console.WriteLine ("Exception in Spawn: " + e);
}

main_loop.Run ();
}

bool ReadStdout (IOChannel source, IOCondition condition)
{
if ((condition & IOCondition.In) == IOCondition.In) {
string txt;
if (source.ReadToEnd (out txt) == IOStatus.Normal)
Console.WriteLine ("[SpawnTest output] " + txt);
}
if ((condition & IOCondition.Hup) == IOCondition.Hup) {
source.Dispose ();
main_loop.Quit ();
return true;
}
return true;
}
}

I'd appreciate it if anyone who has been missing this functionality in Gtk# would try it out and let me know any issues you find, or places the API can be improved.

Thursday, November 8, 2007

Exert 0.1

I've spent a little spare time hacking on exert recently and have reached the point where it has all the features I use from my online running log. I decided to switch over to using it for my log, so that means I need to maintain database compat from now on. I figured I might as well release it in case anyone else was interested in playing with it.

There's a source tarball available, and I used the opensuse build service to provide packages for 10.3 and fedora. Enjoy.

Friday, October 19, 2007

Moko Bindings

One of the comments on my last blog entry suggested a libmokoui binding. Since it was a nice small target, I went ahead and whipped up a binding for it this afternoon. It took me longer to write the tutorial I added to the wiki than it did to produce the binding.

Granted this was a very simple binding, since it is small and the source code was written perfectly for the GAPI parser's consumption. It also has no auto* magic. The tarball contains generated sources which could be copied into your project and compiled and installed as a private assembly. There is really no point to GAC magic for an assembly with no guarantees.

Friday, October 5, 2007

Bind this...

We are looking to add to the already impressive list of libraries accessible from mono. If you have any special requests of the latest and greatest libraries which you like to access from the sexy managed language of your choice, please let us know your needs so we can prioritize our efforts.

You can make your wishes known by commenting on this blog entry, mailing gtk-sharp-list@lists.ximian.com, filing a bug report, or writing on a cocktail napkin and mailing it to us, if you can figure out where we live.

Wednesday, October 3, 2007

GInterface Implementation

Finally "finished" the framework for GInterface registration in Gtk# this week. I wrote up a small tutorial and API description. It points to the small test application I wrote to demonstrate TreeModel implementation, which is the most common reason people have requested GInterface registration for the past few years.

Here's a screenshot of the sample which uses reflection to display the assemblies, types, and members in the application's AppDomain.


Friday, September 7, 2007

Reflection: a Cautionary Tale

Back in the day, I needed a mechanism to execute a method for a class for each new subclass of that type. Class constructors were not sufficient, because they are only run once per type, not once for every subclass of that type.

I decided to annotate the init method with an attribute and use reflection to lookup the method. When we register a new GType, we scan the class hierarchy for private static methods with a GLib.ClassInitializerAttribute and invoke any that exist. We use a similar mechanism to hook overridden virtual methods into the GObject class vtables for signal default handlers using the GLib.DefaultSignalHandlerAttribute.

This strategy works, but it turns out to be pretty suboptimal, especially from a memory usage standpoint. In order to find the methods with [ClassInitializer] defined, we had to load all the private static methods in the type hierarchy, and then iterate over them to look for the attribute. This caused a pretty substantial memory spike for types like Gtk.Widget which have a ton of static method delegate implementations for signal marshaling.

The root of the error was in not recognizing that the Class init problem is a one-to-one relationship of class to method, where the signal delegate problem I borrowed from is a one-to-many scenario. There is a [DefaultSignalHandler] method for each signal defined by a class.

To improve the mechanism, I added a GLib.TypeInitializerAttribute which takes a type and method name argument. With this attribute applied to a type declaration, we can lookup the specific methods by name and avoid loading all the static methods in the entire class hierarchy. This feature is now committed to trunk and the branch svn.

Since we have released the GLib.ClassInitializerAttribute as public API in a stable release, I couldn't just remove the reflection for it, even though it is unlikely that anyone out there really discovered the feature and is using it. In order to make it possible for subclass authors to avoid the reflection step, I also added the GLib.IgnoreClassInitializersAttribute which can be applied to any assemblies which contain GLib.Object subclass declarations. Svn trunk and branch add this attribute to all the gtk-sharp and gnome-sharp assemblies, so that all the types defined by the packages avoid this reflection overhead. The internal usage of [ClassInitializer] has been ported to [TypeInitializer] as well.

Thanks to Lluis for identifying the issue and Paolo for his usual insightful feedback in alternative approaches to the functionality. Lluis also helped refine the implementation of the [ClassInitializer] back-compat mechanism. My understanding is that the recent changes reduced MonoDevelop startup memory usage by about a MB.

Monday, August 13, 2007

Change change change

After living with 4 German Shepherds for over 10 years, the past year has held a lot of painful if not unexpected changes for Sherry and I. We lost OD last fall at ten and a half. This summer was particularly bad, losing our 11 year old JR just two weeks after 13 year old Maggie.

Sherry, Qman, and I have sort of been moping around the house for the last month. It's amazing how empty a house can feel.

That all changed Wednesday night.



It's equally amazing how quickly a 3 month old puppy can fill up a house. Her name is Beebee. We haven't had a puppy in the house in over 11 years. The frantic dashes to the back yard during housebreaking. The brief periods of high-energy romping separated by hours of food-induced comas.

Qman has not been all that interested in playing her little puppy games, but has been very tolerant of her. At times, it seems like he's just laying there rolling his eyes at her. She has a pretty amazing personality. Extremely friendly and confident, and the shepherd drive to please is already evident. We are really looking forward to watching her develop and anticipating the fun we'll have earning obedience, agility, and tracking titles.

Oops, time to take her out back again!