diff --git a/ChangeLog b/ChangeLog index b2aaea447..e0f972c7d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2004-01-18 Peter Williams + + * glib/Marshaller.cs (ArrayPtrToArgv, ArgvToArrayPtr): new + functions for marshalling and unmarshalling string arrays + to/from char **. Not pretty, but lets us call gtk_init() + in Gtk. + + * gtk/Application.cs (do_init): New helper function to handle + passing args to Gtk. Uses above functions. + (Init): Use do_init, take a new progname parameter. + (InitCheck): Same. + 2004-01-18 Mike Kestner * gtk/Gtk.metadata : mark TreeSelection.GetSelectedRows return diff --git a/doc/ChangeLog b/doc/ChangeLog index fe2778d5f..862e5ffd4 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,8 @@ +2003-01-13 Peter Williams + + * en/Gtk/Application.xml: Update Init, InitCheck functions + for new progname argument. Fix a paste-o in the docs for InitCheck. + 2004-01-13 John Luke * en/Gtk/TreeSelection.xml: add example diff --git a/doc/en/Gtk/Application.xml b/doc/en/Gtk/Application.xml index be266e88c..36af90a55 100644 --- a/doc/en/Gtk/Application.xml +++ b/doc/en/Gtk/Application.xml @@ -143,16 +143,18 @@ void LongComputation () - + Method System.Void + Initializes Gtk# for operation. + The name of your program The arguments to pass to the toolkit @@ -164,7 +166,7 @@ void LongComputation () This function will terminate your program if it was unable to initialize the GUI for some reason. If you want your program to fall back to a textual interface you want to - call instead. + call instead. The args values will be modified after Gtk has removed the @@ -174,18 +176,20 @@ void LongComputation () - + Method System.Boolean + Initializes Gtk# for operation, probes window system. true if the toolkit was initialized, false if the windowing system can not be initilized. + The name of your program The arguments to pass to the toolkit @@ -196,12 +200,6 @@ void LongComputation () toolkit could not be initialized. If you do not want to do dual GUI/text applications, you can use instead. - - This function will terminate your program if it was unable - to initialize the GUI for some reason. If you want your - program to fall back to a textual interface you want to - call instead. - @@ -224,11 +222,11 @@ void LongComputation () This function will terminate your program if it was unable to initialize the GUI for some reason. If you want your program to fall back to a textual interface you want to - call instead. + call instead. If you want to pass arguments from the command line use - the + the method instead. @@ -268,4 +266,4 @@ void LongComputation () - \ No newline at end of file + diff --git a/glib/Marshaller.cs b/glib/Marshaller.cs index 003255009..9fe9ffc1b 100644 --- a/glib/Marshaller.cs +++ b/glib/Marshaller.cs @@ -52,6 +52,107 @@ namespace GLibSharp { return g_strdup (str); } + // Argv marshalling -- unpleasantly complex, but + // don't know of a better way to do it. + // + // Currently, the 64-bit cleanliness is + // hypothetical. It's also ugly, but I don't know of a + // construct to handle both 32 and 64 bitness + // transparently, since we need to alloc buffers of + // [native pointer size] * [count] bytes. + + [DllImport("libglib-2.0-0.dll")] + static extern IntPtr g_malloc(ulong size); + + static bool check_sixtyfour () { + int szint = Marshal.SizeOf (typeof (int)); + int szlong = Marshal.SizeOf (typeof (long)); + int szptr = IntPtr.Size; + + if (szptr == szint) + return false; + if (szptr == szlong) + return true; + + throw new Exception ("Pointers are neither int- nor long-sized???"); + } + + static IntPtr make_buf_32 (string[] args) + { + int[] ptrs = new int[args.Length]; + + for (int i = 0; i < args.Length; i++) + ptrs[i] = (int) Marshal.StringToHGlobalAuto (args[i]); + + IntPtr buf = g_malloc ((ulong) Marshal.SizeOf(typeof(string)) * + (ulong) args.Length); + Marshal.Copy (ptrs, 0, buf, ptrs.Length); + return buf; + } + + static IntPtr make_buf_64 (string[] args) + { + long[] ptrs = new long[args.Length]; + + for (int i = 0; i < args.Length; i++) + ptrs[i] = (long) Marshal.StringToHGlobalAuto (args[i]); + + IntPtr buf = g_malloc ((ulong) Marshal.SizeOf(typeof(string)) * + (ulong) args.Length); + Marshal.Copy (ptrs, 0, buf, ptrs.Length); + return buf; + } + + public static IntPtr ArgvToArrayPtr (string[] args) + { + if (args.Length == 0) + return IntPtr.Zero; + + if (check_sixtyfour ()) + return make_buf_64 (args); + + return make_buf_32 (args); + } + + // should we be freeing these pointers? they're marshalled + // from our own strings, so I think not ... + + static string[] unmarshal_32 (IntPtr buf, int argc) + { + int[] ptrs = new int[argc]; + string[] args = new string[argc]; + + Marshal.Copy (buf, ptrs, 0, argc); + + for (int i = 0; i < ptrs.Length; i++) + args[i] = Marshal.PtrToStringAuto ((IntPtr) ptrs[i]); + + return args; + } + + static string[] unmarshal_64 (IntPtr buf, int argc) + { + long[] ptrs = new long[argc]; + string[] args = new string[argc]; + + Marshal.Copy (buf, ptrs, 0, argc); + + for (int i = 0; i < ptrs.Length; i++) + args[i] = Marshal.PtrToStringAuto ((IntPtr) ptrs[i]); + + return args; + } + + public static string[] ArrayPtrToArgv (IntPtr array, int argc) + { + if (argc == 0) + return new string[0]; + + if (check_sixtyfour ()) + return unmarshal_64 (array, argc); + + return unmarshal_32 (array, argc); + } } } diff --git a/gtk/Application.cs b/gtk/Application.cs index ab68c8ee3..5094cce65 100755 --- a/gtk/Application.cs +++ b/gtk/Application.cs @@ -20,28 +20,57 @@ namespace Gtk { } [DllImport("libgtk-win32-2.0-0.dll")] - static extern void gtk_init (int argc, IntPtr argv); + static extern void gtk_init (ref int argc, ref IntPtr argv); + + [DllImport("libgtk-win32-2.0-0.dll")] + static extern bool gtk_init_check (ref int argc, ref IntPtr argv); public static void Init () { - gtk_init (0, new IntPtr(0)); + IntPtr argv = new IntPtr(0); + int argc = 0; + + gtk_init (ref argc, ref argv); } - [DllImport("libgtk-win32-2.0-0.dll")] - static extern void gtk_init (ref int argc, ref String[] argv); - [DllImport("libgtk-win32-2.0-0.dll")] - static extern bool gtk_init_check (ref int argc, ref String[] argv); - - public static void Init (ref string[] args) + static bool do_init (string progname, ref string[] args, bool check) { - int argc = args.Length; - gtk_init (ref argc, ref args); + bool res = false; + string[] progargs = new string[args.Length + 1]; + + progargs[0] = progname; + args.CopyTo (progargs, 1); + + IntPtr buf = GLibSharp.Marshaller.ArgvToArrayPtr (progargs); + int argc = progargs.Length; + + if (check) + res = gtk_init_check (ref argc, ref buf); + else + gtk_init (ref argc, ref buf); + + // copy back the resulting argv, minus argv[0], which we're + // not interested in. + + if (argc == 0) + args = new string[0]; + else { + progargs = GLibSharp.Marshaller.ArrayPtrToArgv (buf, argc); + args = new string[argc - 1]; + Array.Copy (progargs, 1, args, 0, argc - 1); + } + + return res; } - public static bool InitCheck (ref string[] args) + public static void Init (string progname, ref string[] args) { - int argc = args.Length; - return gtk_init_check (ref argc, ref args); + do_init (progname, ref args, false); + } + + public static bool InitCheck (string progname, ref string[] args) + { + return do_init (progname, ref args, true); } [DllImport("libgtk-win32-2.0-0.dll")]